blob: d2e81d0fcd0f472f1ac00dc20f3e900c6b39a71b [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"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010033#include "hda_patch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020063#ifdef CONFIG_SND_DEBUG
64 ALC880_TEST,
65#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010066 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020067 ALC880_MODEL_LAST /* last tag */
68};
69
70/* ALC260 models */
71enum {
72 ALC260_BASIC,
73 ALC260_HP,
Kailang Yangdf694da2005-12-05 19:42:22 +010074 ALC260_HP_3013,
75 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010076 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020077 ALC260_WILL,
78 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010079#ifdef CONFIG_SND_DEBUG
80 ALC260_TEST,
81#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010082 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020083 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084};
85
Kailang Yangdf694da2005-12-05 19:42:22 +010086/* ALC262 models */
87enum {
88 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020089 ALC262_HIPPO,
90 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010091 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020092 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010093 ALC262_HP_BPC_D7000_WL,
94 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010095 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010096 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020097 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +020098 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +020099 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200100 ALC262_ULTRA,
Kailang Yangdf694da2005-12-05 19:42:22 +0100101 ALC262_AUTO,
102 ALC262_MODEL_LAST /* last tag */
103};
104
Kailang Yanga361d842007-06-05 12:30:55 +0200105/* ALC268 models */
106enum {
107 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200108 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200109 ALC268_ACER,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100110 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100111 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100112#ifdef CONFIG_SND_DEBUG
113 ALC268_TEST,
114#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200115 ALC268_AUTO,
116 ALC268_MODEL_LAST /* last tag */
117};
118
Kailang Yangf6a92242007-12-13 16:52:54 +0100119/* ALC269 models */
120enum {
121 ALC269_BASIC,
122 ALC269_AUTO,
123 ALC269_MODEL_LAST /* last tag */
124};
125
Kailang Yangdf694da2005-12-05 19:42:22 +0100126/* ALC861 models */
127enum {
128 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200129 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100130 ALC861_3ST_DIG,
131 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200132 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200133 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200134 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100135 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100136 ALC861_AUTO,
137 ALC861_MODEL_LAST,
138};
139
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100140/* ALC861-VD models */
141enum {
142 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200143 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100144 ALC861VD_3ST,
145 ALC861VD_3ST_DIG,
146 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200147 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200148 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200149 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100150 ALC861VD_AUTO,
151 ALC861VD_MODEL_LAST,
152};
153
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200154/* ALC662 models */
155enum {
156 ALC662_3ST_2ch_DIG,
157 ALC662_3ST_6ch_DIG,
158 ALC662_3ST_6ch,
159 ALC662_5ST_DIG,
160 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200161 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100162 ALC662_ASUS_EEEPC_EP20,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200163 ALC662_AUTO,
164 ALC662_MODEL_LAST,
165};
166
Kailang Yangdf694da2005-12-05 19:42:22 +0100167/* ALC882 models */
168enum {
169 ALC882_3ST_DIG,
170 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200171 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200172 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200173 ALC882_TARGA,
174 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200175 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100176 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200177 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200178 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200179 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100180 ALC882_MODEL_LAST,
181};
182
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200183/* ALC883 models */
184enum {
185 ALC883_3ST_2ch_DIG,
186 ALC883_3ST_6ch_DIG,
187 ALC883_3ST_6ch,
188 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200189 ALC883_TARGA_DIG,
190 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200191 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200192 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200193 ALC883_MEDION,
Kailang Yang272a5272007-05-14 11:00:38 +0200194 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100195 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200196 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200197 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200198 ALC888_LENOVO_MS7195_DIG,
199 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200200 ALC888_6ST_HP,
201 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100202 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100203 ALC883_MITAC,
Jiang zhe368c7a92008-03-04 11:20:33 +0100204 ALC883_CLEVO_M720R,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200205 ALC883_AUTO,
206 ALC883_MODEL_LAST,
207};
208
Kailang Yangdf694da2005-12-05 19:42:22 +0100209/* for GPIO Poll */
210#define GPIO_MASK 0x03
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212struct alc_spec {
213 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100214 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 unsigned int num_mixers;
216
Kailang Yangdf694da2005-12-05 19:42:22 +0100217 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200218 * don't forget NULL
219 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200220 */
221 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Takashi Iwai16ded522005-06-10 19:58:24 +0200223 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 struct hda_pcm_stream *stream_analog_playback;
225 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100226 struct hda_pcm_stream *stream_analog_alt_playback;
227 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200229 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 struct hda_pcm_stream *stream_digital_playback;
231 struct hda_pcm_stream *stream_digital_capture;
232
233 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200234 struct hda_multi_out multiout; /* playback set-up
235 * max_channels, dacs must be set
236 * dig_out_nid and hp_nid are optional
237 */
Takashi Iwai63300792008-01-24 15:31:36 +0100238 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 /* capture */
241 unsigned int num_adc_nids;
242 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100243 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200244 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200247 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 const struct hda_input_mux *input_mux;
249 unsigned int cur_mux[3];
250
251 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100252 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200254 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100257 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200258
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200259 /* dynamic controls, init_verbs and input_mux */
260 struct auto_pin_cfg autocfg;
261 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100262 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200263 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200264 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100265
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100266 /* hooks */
267 void (*init_hook)(struct hda_codec *codec);
268 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
269
Takashi Iwai834be882006-03-01 14:16:17 +0100270 /* for pin sensing */
271 unsigned int sense_updated: 1;
272 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100273 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200274
Takashi Iwai2134ea42008-01-10 16:53:55 +0100275 /* for virtual master */
276 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200277#ifdef CONFIG_SND_HDA_POWER_SAVE
278 struct hda_loopback_check loopback;
279#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100280};
281
282/*
283 * configuration template - to be copied to the spec instance
284 */
285struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200286 struct snd_kcontrol_new *mixers[5]; /* should be identical size
287 * with spec
288 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100289 const struct hda_verb *init_verbs[5];
290 unsigned int num_dacs;
291 hda_nid_t *dac_nids;
292 hda_nid_t dig_out_nid; /* optional */
293 hda_nid_t hp_nid; /* optional */
294 unsigned int num_adc_nids;
295 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100296 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100297 hda_nid_t dig_in_nid;
298 unsigned int num_channel_mode;
299 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200300 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200301 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100302 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100303 void (*unsol_event)(struct hda_codec *, unsigned int);
304 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200305#ifdef CONFIG_SND_HDA_POWER_SAVE
306 struct hda_amp_list *loopbacks;
307#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308};
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311/*
312 * input MUX handling
313 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200314static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
315 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
318 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200319 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
320 if (mux_idx >= spec->num_mux_defs)
321 mux_idx = 0;
322 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200325static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
326 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
329 struct alc_spec *spec = codec->spec;
330 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
331
332 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
333 return 0;
334}
335
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200336static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
337 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
340 struct alc_spec *spec = codec->spec;
341 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200342 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100343 hda_nid_t nid = spec->capsrc_nids ?
344 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200345 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100346 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/*
351 * channel mode setting
352 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200353static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
354 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
357 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100358 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
359 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200362static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
363 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
366 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100367 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200368 spec->num_channel_mode,
369 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200372static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
373 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
375 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
376 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200377 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
378 spec->num_channel_mode,
379 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200380 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200381 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
382 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100386 * Control the mode of pin widget settings via the mixer. "pc" is used
387 * instead of "%" to avoid consequences of accidently treating the % as
388 * being part of a format specifier. Maximum allowed length of a value is
389 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100390 *
391 * Note: some retasking pin complexes seem to ignore requests for input
392 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
393 * are requested. Therefore order this list so that this behaviour will not
394 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200395 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
396 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200397 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100398static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100399 "Mic 50pc bias", "Mic 80pc bias",
400 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100401};
402static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100403 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100404};
405/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200406 * in the pin being assumed to be exclusively an input or an output pin. In
407 * addition, "input" pins may or may not process the mic bias option
408 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
409 * accept requests for bias as of chip versions up to March 2006) and/or
410 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100411 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200412#define ALC_PIN_DIR_IN 0x00
413#define ALC_PIN_DIR_OUT 0x01
414#define ALC_PIN_DIR_INOUT 0x02
415#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
416#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100417
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200418/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100419 * For each direction the minimum and maximum values are given.
420 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200421static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100422 { 0, 2 }, /* ALC_PIN_DIR_IN */
423 { 3, 4 }, /* ALC_PIN_DIR_OUT */
424 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200425 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
426 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100427};
428#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
429#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
430#define alc_pin_mode_n_items(_dir) \
431 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
432
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200433static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
434 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200435{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100436 unsigned int item_num = uinfo->value.enumerated.item;
437 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
438
439 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200440 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100441 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
442
443 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
444 item_num = alc_pin_mode_min(dir);
445 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200446 return 0;
447}
448
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200449static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
450 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200451{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100452 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
454 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100455 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200456 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200457 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
458 AC_VERB_GET_PIN_WIDGET_CONTROL,
459 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200460
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100461 /* Find enumerated value for current pinctl setting */
462 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200463 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100464 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200465 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100466 return 0;
467}
468
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200469static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
470 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100471{
472 signed int change;
473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
474 hda_nid_t nid = kcontrol->private_value & 0xffff;
475 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
476 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200477 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
478 AC_VERB_GET_PIN_WIDGET_CONTROL,
479 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100480
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200481 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100482 val = alc_pin_mode_min(dir);
483
484 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100485 if (change) {
486 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200487 snd_hda_codec_write_cache(codec, nid, 0,
488 AC_VERB_SET_PIN_WIDGET_CONTROL,
489 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100490
491 /* Also enable the retasking pin's input/output as required
492 * for the requested pin mode. Enum values of 2 or less are
493 * input modes.
494 *
495 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200496 * reduces noise slightly (particularly on input) so we'll
497 * do it. However, having both input and output buffers
498 * enabled simultaneously doesn't seem to be problematic if
499 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100500 */
501 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200502 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
503 HDA_AMP_MUTE, HDA_AMP_MUTE);
504 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
505 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100506 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200507 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
508 HDA_AMP_MUTE, HDA_AMP_MUTE);
509 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
510 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100511 }
512 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200513 return change;
514}
515
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100516#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200517 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100518 .info = alc_pin_mode_info, \
519 .get = alc_pin_mode_get, \
520 .put = alc_pin_mode_put, \
521 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100522
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100523/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
524 * together using a mask with more than one bit set. This control is
525 * currently used only by the ALC260 test model. At this stage they are not
526 * needed for any "production" models.
527 */
528#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200529#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200530
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200531static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
532 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100533{
534 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
535 hda_nid_t nid = kcontrol->private_value & 0xffff;
536 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
537 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200538 unsigned int val = snd_hda_codec_read(codec, nid, 0,
539 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100540
541 *valp = (val & mask) != 0;
542 return 0;
543}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200544static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
545 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100546{
547 signed int change;
548 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
549 hda_nid_t nid = kcontrol->private_value & 0xffff;
550 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
551 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200552 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
553 AC_VERB_GET_GPIO_DATA,
554 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100555
556 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200557 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
558 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100559 gpio_data &= ~mask;
560 else
561 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200562 snd_hda_codec_write_cache(codec, nid, 0,
563 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100564
565 return change;
566}
567#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
568 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
569 .info = alc_gpio_data_info, \
570 .get = alc_gpio_data_get, \
571 .put = alc_gpio_data_put, \
572 .private_value = nid | (mask<<16) }
573#endif /* CONFIG_SND_DEBUG */
574
Jonathan Woithe92621f12006-02-28 11:47:47 +0100575/* A switch control to allow the enabling of the digital IO pins on the
576 * ALC260. This is incredibly simplistic; the intention of this control is
577 * to provide something in the test model allowing digital outputs to be
578 * identified if present. If models are found which can utilise these
579 * outputs a more complete mixer control can be devised for those models if
580 * necessary.
581 */
582#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200583#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200584
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200585static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
586 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100587{
588 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
589 hda_nid_t nid = kcontrol->private_value & 0xffff;
590 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
591 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200592 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100593 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100594
595 *valp = (val & mask) != 0;
596 return 0;
597}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200598static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
599 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100600{
601 signed int change;
602 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
603 hda_nid_t nid = kcontrol->private_value & 0xffff;
604 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
605 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200606 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100607 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200608 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100609
610 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200611 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100612 if (val==0)
613 ctrl_data &= ~mask;
614 else
615 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200616 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
617 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100618
619 return change;
620}
621#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
622 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
623 .info = alc_spdif_ctrl_info, \
624 .get = alc_spdif_ctrl_get, \
625 .put = alc_spdif_ctrl_put, \
626 .private_value = nid | (mask<<16) }
627#endif /* CONFIG_SND_DEBUG */
628
Jonathan Woithef8225f62008-01-08 12:16:54 +0100629/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
630 * Again, this is only used in the ALC26x test models to help identify when
631 * the EAPD line must be asserted for features to work.
632 */
633#ifdef CONFIG_SND_DEBUG
634#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
635
636static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
637 struct snd_ctl_elem_value *ucontrol)
638{
639 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
640 hda_nid_t nid = kcontrol->private_value & 0xffff;
641 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
642 long *valp = ucontrol->value.integer.value;
643 unsigned int val = snd_hda_codec_read(codec, nid, 0,
644 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
645
646 *valp = (val & mask) != 0;
647 return 0;
648}
649
650static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
651 struct snd_ctl_elem_value *ucontrol)
652{
653 int change;
654 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
655 hda_nid_t nid = kcontrol->private_value & 0xffff;
656 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
657 long val = *ucontrol->value.integer.value;
658 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
659 AC_VERB_GET_EAPD_BTLENABLE,
660 0x00);
661
662 /* Set/unset the masked control bit(s) as needed */
663 change = (!val ? 0 : mask) != (ctrl_data & mask);
664 if (!val)
665 ctrl_data &= ~mask;
666 else
667 ctrl_data |= mask;
668 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
669 ctrl_data);
670
671 return change;
672}
673
674#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
675 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
676 .info = alc_eapd_ctrl_info, \
677 .get = alc_eapd_ctrl_get, \
678 .put = alc_eapd_ctrl_put, \
679 .private_value = nid | (mask<<16) }
680#endif /* CONFIG_SND_DEBUG */
681
Kailang Yangdf694da2005-12-05 19:42:22 +0100682/*
683 * set up from the preset table
684 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200685static void setup_preset(struct alc_spec *spec,
686 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100687{
688 int i;
689
690 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
691 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200692 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
693 i++)
694 spec->init_verbs[spec->num_init_verbs++] =
695 preset->init_verbs[i];
Kailang Yangdf694da2005-12-05 19:42:22 +0100696
697 spec->channel_mode = preset->channel_mode;
698 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200699 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100700
701 spec->multiout.max_channels = spec->channel_mode[0].channels;
702
703 spec->multiout.num_dacs = preset->num_dacs;
704 spec->multiout.dac_nids = preset->dac_nids;
705 spec->multiout.dig_out_nid = preset->dig_out_nid;
706 spec->multiout.hp_nid = preset->hp_nid;
707
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200708 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200709 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200710 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100711 spec->input_mux = preset->input_mux;
712
713 spec->num_adc_nids = preset->num_adc_nids;
714 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100715 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100716 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100717
718 spec->unsol_event = preset->unsol_event;
719 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200720#ifdef CONFIG_SND_HDA_POWER_SAVE
721 spec->loopback.amplist = preset->loopbacks;
722#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100723}
724
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200725/* Enable GPIO mask and set output */
726static struct hda_verb alc_gpio1_init_verbs[] = {
727 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
728 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
729 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
730 { }
731};
732
733static struct hda_verb alc_gpio2_init_verbs[] = {
734 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
735 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
736 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
737 { }
738};
739
Kailang Yangbdd148a2007-05-08 15:19:08 +0200740static struct hda_verb alc_gpio3_init_verbs[] = {
741 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
742 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
743 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
744 { }
745};
746
Kailang Yangc9b58002007-10-16 14:30:01 +0200747static void alc_sku_automute(struct hda_codec *codec)
748{
749 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200750 unsigned int present;
751 unsigned int hp_nid = spec->autocfg.hp_pins[0];
752 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
753
754 /* need to execute and sync at first */
755 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
756 present = snd_hda_codec_read(codec, hp_nid, 0,
757 AC_VERB_GET_PIN_SENSE, 0);
758 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100759 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
760 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200761}
762
763/* unsolicited event for HP jack sensing */
764static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
765{
766 if (codec->vendor_id == 0x10ec0880)
767 res >>= 28;
768 else
769 res >>= 26;
770 if (res != ALC880_HP_EVENT)
771 return;
772
773 alc_sku_automute(codec);
774}
775
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200776/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
777 * 31 ~ 16 : Manufacture ID
778 * 15 ~ 8 : SKU ID
779 * 7 ~ 0 : Assembly ID
780 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
781 */
782static void alc_subsystem_id(struct hda_codec *codec,
783 unsigned int porta, unsigned int porte,
784 unsigned int portd)
785{
Kailang Yangc9b58002007-10-16 14:30:01 +0200786 unsigned int ass, tmp, i;
787 unsigned nid;
788 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200789
Kailang Yangc9b58002007-10-16 14:30:01 +0200790 ass = codec->subsystem_id & 0xffff;
791 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
792 goto do_sku;
793
794 /*
795 * 31~30 : port conetcivity
796 * 29~21 : reserve
797 * 20 : PCBEEP input
798 * 19~16 : Check sum (15:1)
799 * 15~1 : Custom
800 * 0 : override
801 */
802 nid = 0x1d;
803 if (codec->vendor_id == 0x10ec0260)
804 nid = 0x17;
805 ass = snd_hda_codec_read(codec, nid, 0,
806 AC_VERB_GET_CONFIG_DEFAULT, 0);
807 if (!(ass & 1) && !(ass & 0x100000))
808 return;
809 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200810 return;
811
Kailang Yangc9b58002007-10-16 14:30:01 +0200812 /* check sum */
813 tmp = 0;
814 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100815 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200816 tmp++;
817 }
818 if (((ass >> 16) & 0xf) != tmp)
819 return;
820do_sku:
821 /*
822 * 0 : override
823 * 1 : Swap Jack
824 * 2 : 0 --> Desktop, 1 --> Laptop
825 * 3~5 : External Amplifier control
826 * 7~6 : Reserved
827 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200828 tmp = (ass & 0x38) >> 3; /* external Amp control */
829 switch (tmp) {
830 case 1:
831 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
832 break;
833 case 3:
834 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
835 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200836 case 7:
837 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
838 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200839 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200840 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200841 case 0x10ec0260:
842 snd_hda_codec_write(codec, 0x0f, 0,
843 AC_VERB_SET_EAPD_BTLENABLE, 2);
844 snd_hda_codec_write(codec, 0x10, 0,
845 AC_VERB_SET_EAPD_BTLENABLE, 2);
846 break;
847 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200848 case 0x10ec0267:
849 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200850 case 0x10ec0269:
851 case 0x10ec0862:
852 case 0x10ec0662:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200853 snd_hda_codec_write(codec, 0x14, 0,
854 AC_VERB_SET_EAPD_BTLENABLE, 2);
855 snd_hda_codec_write(codec, 0x15, 0,
856 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200857 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200858 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200859 switch (codec->vendor_id) {
860 case 0x10ec0260:
861 snd_hda_codec_write(codec, 0x1a, 0,
862 AC_VERB_SET_COEF_INDEX, 7);
863 tmp = snd_hda_codec_read(codec, 0x1a, 0,
864 AC_VERB_GET_PROC_COEF, 0);
865 snd_hda_codec_write(codec, 0x1a, 0,
866 AC_VERB_SET_COEF_INDEX, 7);
867 snd_hda_codec_write(codec, 0x1a, 0,
868 AC_VERB_SET_PROC_COEF,
869 tmp | 0x2010);
870 break;
871 case 0x10ec0262:
872 case 0x10ec0880:
873 case 0x10ec0882:
874 case 0x10ec0883:
875 case 0x10ec0885:
876 case 0x10ec0888:
877 snd_hda_codec_write(codec, 0x20, 0,
878 AC_VERB_SET_COEF_INDEX, 7);
879 tmp = snd_hda_codec_read(codec, 0x20, 0,
880 AC_VERB_GET_PROC_COEF, 0);
881 snd_hda_codec_write(codec, 0x20, 0,
882 AC_VERB_SET_COEF_INDEX, 7);
883 snd_hda_codec_write(codec, 0x20, 0,
884 AC_VERB_SET_PROC_COEF,
885 tmp | 0x2010);
886 break;
887 case 0x10ec0267:
888 case 0x10ec0268:
889 snd_hda_codec_write(codec, 0x20, 0,
890 AC_VERB_SET_COEF_INDEX, 7);
891 tmp = snd_hda_codec_read(codec, 0x20, 0,
892 AC_VERB_GET_PROC_COEF, 0);
893 snd_hda_codec_write(codec, 0x20, 0,
894 AC_VERB_SET_COEF_INDEX, 7);
895 snd_hda_codec_write(codec, 0x20, 0,
896 AC_VERB_SET_PROC_COEF,
897 tmp | 0x3000);
898 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200899 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200900 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200901 break;
902 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200903
Kailang Yang8c427222008-01-10 13:03:59 +0100904 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200905 * when the external headphone out jack is plugged"
906 */
Kailang Yang8c427222008-01-10 13:03:59 +0100907 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200908 return;
909 /*
910 * 10~8 : Jack location
911 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
912 * 14~13: Resvered
913 * 15 : 1 --> enable the function "Mute internal speaker
914 * when the external headphone out jack is plugged"
915 */
916 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +0100917 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +0200918 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +0100919 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +0200920 else
921 return;
922 }
923
924 if (!spec->autocfg.hp_pins[0]) {
925 tmp = (ass >> 11) & 0x3; /* HP to chassis */
926 if (tmp == 0)
927 spec->autocfg.hp_pins[0] = porta;
928 else if (tmp == 1)
929 spec->autocfg.hp_pins[0] = porte;
930 else if (tmp == 2)
931 spec->autocfg.hp_pins[0] = portd;
932 else
933 return;
934 }
935
936 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
937 AC_VERB_SET_UNSOLICITED_ENABLE,
938 AC_USRSP_EN | ALC880_HP_EVENT);
939 spec->unsol_event = alc_sku_unsol_event;
940 spec->init_hook = alc_sku_automute;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200941}
942
Takashi Iwai41e41f12005-06-08 14:48:49 +0200943/*
Takashi Iwaif95474e2007-07-10 00:47:43 +0200944 * Fix-up pin default configurations
945 */
946
947struct alc_pincfg {
948 hda_nid_t nid;
949 u32 val;
950};
951
952static void alc_fix_pincfg(struct hda_codec *codec,
953 const struct snd_pci_quirk *quirk,
954 const struct alc_pincfg **pinfix)
955{
956 const struct alc_pincfg *cfg;
957
958 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
959 if (!quirk)
960 return;
961
962 cfg = pinfix[quirk->value];
963 for (; cfg->nid; cfg++) {
964 int i;
965 u32 val = cfg->val;
966 for (i = 0; i < 4; i++) {
967 snd_hda_codec_write(codec, cfg->nid, 0,
968 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
969 val & 0xff);
970 val >>= 8;
971 }
972 }
973}
974
975/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200976 * ALC880 3-stack model
977 *
978 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200979 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
980 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 */
982
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200983static hda_nid_t alc880_dac_nids[4] = {
984 /* front, rear, clfe, rear_surr */
985 0x02, 0x05, 0x04, 0x03
986};
987
988static hda_nid_t alc880_adc_nids[3] = {
989 /* ADC0-2 */
990 0x07, 0x08, 0x09,
991};
992
993/* The datasheet says the node 0x07 is connected from inputs,
994 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +0100995 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200997static hda_nid_t alc880_adc_nids_alt[2] = {
998 /* ADC1-2 */
999 0x08, 0x09,
1000};
1001
1002#define ALC880_DIGOUT_NID 0x06
1003#define ALC880_DIGIN_NID 0x0a
1004
1005static struct hda_input_mux alc880_capture_source = {
1006 .num_items = 4,
1007 .items = {
1008 { "Mic", 0x0 },
1009 { "Front Mic", 0x3 },
1010 { "Line", 0x2 },
1011 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001013};
1014
1015/* channel source setting (2/6 channel selection for 3-stack) */
1016/* 2ch mode */
1017static struct hda_verb alc880_threestack_ch2_init[] = {
1018 /* set line-in to input, mute it */
1019 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1020 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1021 /* set mic-in to input vref 80%, mute it */
1022 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1023 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 { } /* end */
1025};
1026
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001027/* 6ch mode */
1028static struct hda_verb alc880_threestack_ch6_init[] = {
1029 /* set line-in to output, unmute it */
1030 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1031 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1032 /* set mic-in to output, unmute it */
1033 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1034 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1035 { } /* end */
1036};
1037
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001038static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001039 { 2, alc880_threestack_ch2_init },
1040 { 6, alc880_threestack_ch6_init },
1041};
1042
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001043static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001044 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001045 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001046 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001047 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001048 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1049 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001050 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1051 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1053 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1054 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1055 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1056 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1057 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1058 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1059 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1060 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1061 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001063 {
1064 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1065 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001066 .info = alc_ch_mode_info,
1067 .get = alc_ch_mode_get,
1068 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001069 },
1070 { } /* end */
1071};
1072
1073/* capture mixer elements */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001074static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001075 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1076 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1077 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1078 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1079 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1080 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1081 {
1082 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1083 /* The multiple "Capture Source" controls confuse alsamixer
1084 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001085 */
1086 /* .name = "Capture Source", */
1087 .name = "Input Source",
1088 .count = 3,
1089 .info = alc_mux_enum_info,
1090 .get = alc_mux_enum_get,
1091 .put = alc_mux_enum_put,
1092 },
1093 { } /* end */
1094};
1095
1096/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001097static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001098 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1099 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1100 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1101 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 {
1103 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1104 /* The multiple "Capture Source" controls confuse alsamixer
1105 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 */
1107 /* .name = "Capture Source", */
1108 .name = "Input Source",
1109 .count = 2,
1110 .info = alc_mux_enum_info,
1111 .get = alc_mux_enum_get,
1112 .put = alc_mux_enum_put,
1113 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 { } /* end */
1115};
1116
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001117
1118
1119/*
1120 * ALC880 5-stack model
1121 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001122 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1123 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001124 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1125 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1126 */
1127
1128/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001129static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001130 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001131 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 { } /* end */
1133};
1134
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001135/* channel source setting (6/8 channel selection for 5-stack) */
1136/* 6ch mode */
1137static struct hda_verb alc880_fivestack_ch6_init[] = {
1138 /* set line-in to input, mute it */
1139 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1140 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001141 { } /* end */
1142};
1143
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001144/* 8ch mode */
1145static struct hda_verb alc880_fivestack_ch8_init[] = {
1146 /* set line-in to output, unmute it */
1147 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1148 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1149 { } /* end */
1150};
1151
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001152static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001153 { 6, alc880_fivestack_ch6_init },
1154 { 8, alc880_fivestack_ch8_init },
1155};
1156
1157
1158/*
1159 * ALC880 6-stack model
1160 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001161 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1162 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001163 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1164 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1165 */
1166
1167static hda_nid_t alc880_6st_dac_nids[4] = {
1168 /* front, rear, clfe, rear_surr */
1169 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001170};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001171
1172static struct hda_input_mux alc880_6stack_capture_source = {
1173 .num_items = 4,
1174 .items = {
1175 { "Mic", 0x0 },
1176 { "Front Mic", 0x1 },
1177 { "Line", 0x2 },
1178 { "CD", 0x4 },
1179 },
1180};
1181
1182/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001183static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001184 { 8, NULL },
1185};
1186
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001187static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001188 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001189 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001190 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001191 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001192 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1193 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001194 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1195 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001196 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001197 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001198 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1199 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1200 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1201 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1202 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1203 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1204 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1205 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1206 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1207 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001208 {
1209 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1210 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001211 .info = alc_ch_mode_info,
1212 .get = alc_ch_mode_get,
1213 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001214 },
1215 { } /* end */
1216};
1217
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001218
1219/*
1220 * ALC880 W810 model
1221 *
1222 * W810 has rear IO for:
1223 * Front (DAC 02)
1224 * Surround (DAC 03)
1225 * Center/LFE (DAC 04)
1226 * Digital out (06)
1227 *
1228 * The system also has a pair of internal speakers, and a headphone jack.
1229 * These are both connected to Line2 on the codec, hence to DAC 02.
1230 *
1231 * There is a variable resistor to control the speaker or headphone
1232 * volume. This is a hardware-only device without a software API.
1233 *
1234 * Plugging headphones in will disable the internal speakers. This is
1235 * implemented in hardware, not via the driver using jack sense. In
1236 * a similar fashion, plugging into the rear socket marked "front" will
1237 * disable both the speakers and headphones.
1238 *
1239 * For input, there's a microphone jack, and an "audio in" jack.
1240 * These may not do anything useful with this driver yet, because I
1241 * haven't setup any initialization verbs for these yet...
1242 */
1243
1244static hda_nid_t alc880_w810_dac_nids[3] = {
1245 /* front, rear/surround, clfe */
1246 0x02, 0x03, 0x04
1247};
1248
1249/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001250static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001251 { 6, NULL }
1252};
1253
1254/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001255static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001256 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001257 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001258 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001259 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001260 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1261 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001262 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1263 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001264 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1265 { } /* end */
1266};
1267
1268
1269/*
1270 * Z710V model
1271 *
1272 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001273 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1274 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001275 */
1276
1277static hda_nid_t alc880_z71v_dac_nids[1] = {
1278 0x02
1279};
1280#define ALC880_Z71V_HP_DAC 0x03
1281
1282/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001283static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001284 { 2, NULL }
1285};
1286
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001287static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001289 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001290 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001291 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001292 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1293 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1295 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1296 { } /* end */
1297};
1298
1299
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001300/*
1301 * ALC880 F1734 model
1302 *
1303 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1304 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1305 */
1306
1307static hda_nid_t alc880_f1734_dac_nids[1] = {
1308 0x03
1309};
1310#define ALC880_F1734_HP_DAC 0x02
1311
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001312static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001313 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001314 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001315 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1316 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001317 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1318 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001319 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1320 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001321 { } /* end */
1322};
1323
Takashi Iwai937b4162008-02-11 14:52:36 +01001324static struct hda_input_mux alc880_f1734_capture_source = {
1325 .num_items = 2,
1326 .items = {
1327 { "Mic", 0x1 },
1328 { "CD", 0x4 },
1329 },
1330};
1331
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001332
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001333/*
1334 * ALC880 ASUS model
1335 *
1336 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1337 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1338 * Mic = 0x18, Line = 0x1a
1339 */
1340
1341#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1342#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1343
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001344static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001345 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001346 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001347 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001348 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001349 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1350 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001351 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1352 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001353 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1354 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1355 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1356 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1357 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1358 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001359 {
1360 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1361 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001362 .info = alc_ch_mode_info,
1363 .get = alc_ch_mode_get,
1364 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001365 },
1366 { } /* end */
1367};
1368
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001369/*
1370 * ALC880 ASUS W1V model
1371 *
1372 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1373 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1374 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1375 */
1376
1377/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001378static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001379 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1380 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001381 { } /* end */
1382};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001383
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001384/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001385static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001386 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1387 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1388 { } /* end */
1389};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001390
Kailang Yangdf694da2005-12-05 19:42:22 +01001391/* TCL S700 */
1392static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1393 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1394 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1395 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1396 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1397 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1398 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1399 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1400 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1401 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1402 {
1403 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1404 /* The multiple "Capture Source" controls confuse alsamixer
1405 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001406 */
1407 /* .name = "Capture Source", */
1408 .name = "Input Source",
1409 .count = 1,
1410 .info = alc_mux_enum_info,
1411 .get = alc_mux_enum_get,
1412 .put = alc_mux_enum_put,
1413 },
1414 { } /* end */
1415};
1416
Kailang Yangccc656c2006-10-17 12:32:26 +02001417/* Uniwill */
1418static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001419 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1420 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1421 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1422 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001423 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1424 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1425 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1426 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1427 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1428 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1429 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1430 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1431 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1432 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1433 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1434 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1435 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1436 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1437 {
1438 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1439 .name = "Channel Mode",
1440 .info = alc_ch_mode_info,
1441 .get = alc_ch_mode_get,
1442 .put = alc_ch_mode_put,
1443 },
1444 { } /* end */
1445};
1446
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001447static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1448 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1449 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1450 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1451 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1452 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1453 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1454 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1455 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1456 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1457 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1458 { } /* end */
1459};
1460
Kailang Yangccc656c2006-10-17 12:32:26 +02001461static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001462 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1463 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1464 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1465 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001466 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1467 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1468 { } /* end */
1469};
1470
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001472 * virtual master controls
1473 */
1474
1475/*
1476 * slave controls for virtual master
1477 */
1478static const char *alc_slave_vols[] = {
1479 "Front Playback Volume",
1480 "Surround Playback Volume",
1481 "Center Playback Volume",
1482 "LFE Playback Volume",
1483 "Side Playback Volume",
1484 "Headphone Playback Volume",
1485 "Speaker Playback Volume",
1486 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001487 "Line-Out Playback Volume",
1488 NULL,
1489};
1490
1491static const char *alc_slave_sws[] = {
1492 "Front Playback Switch",
1493 "Surround Playback Switch",
1494 "Center Playback Switch",
1495 "LFE Playback Switch",
1496 "Side Playback Switch",
1497 "Headphone Playback Switch",
1498 "Speaker Playback Switch",
1499 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001500 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001501 NULL,
1502};
1503
1504/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001505 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 */
1507static int alc_build_controls(struct hda_codec *codec)
1508{
1509 struct alc_spec *spec = codec->spec;
1510 int err;
1511 int i;
1512
1513 for (i = 0; i < spec->num_mixers; i++) {
1514 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1515 if (err < 0)
1516 return err;
1517 }
1518
1519 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001520 err = snd_hda_create_spdif_out_ctls(codec,
1521 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 if (err < 0)
1523 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001524 err = snd_hda_create_spdif_share_sw(codec,
1525 &spec->multiout);
1526 if (err < 0)
1527 return err;
1528 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
1530 if (spec->dig_in_nid) {
1531 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1532 if (err < 0)
1533 return err;
1534 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001535
1536 /* if we have no master control, let's create it */
1537 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001538 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001539 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001540 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001541 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001542 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001543 if (err < 0)
1544 return err;
1545 }
1546 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1547 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1548 NULL, alc_slave_sws);
1549 if (err < 0)
1550 return err;
1551 }
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 return 0;
1554}
1555
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557/*
1558 * initialize the codec volumes, etc
1559 */
1560
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001561/*
1562 * generic initialization of ADC, input mixers and output mixers
1563 */
1564static struct hda_verb alc880_volume_init_verbs[] = {
1565 /*
1566 * Unmute ADC0-2 and set the default input to mic-in
1567 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001568 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001569 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001570 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001571 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001572 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001573 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001575 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1576 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001577 * Note: PASD motherboards uses the Line In 2 as the input for front
1578 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001580 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001581 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1582 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1583 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1584 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1585 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1586 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1587 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001589 /*
1590 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001592 /* set vol=0 to output mixers */
1593 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1594 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1595 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1596 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1597 /* set up input amps for analog loopback */
1598 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001599 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1600 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001601 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1602 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001603 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1604 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001605 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1606 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 { }
1609};
1610
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001611/*
1612 * 3-stack pin configuration:
1613 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1614 */
1615static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1616 /*
1617 * preset connection lists of input pins
1618 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1619 */
1620 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1621 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1622 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1623
1624 /*
1625 * Set pin mode and muting
1626 */
1627 /* set front pin widgets 0x14 for output */
1628 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1629 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1630 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1631 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1632 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1633 /* Mic2 (as headphone out) for HP output */
1634 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1635 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1636 /* Line In pin widget for input */
1637 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1638 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1639 /* Line2 (as front mic) pin widget for input and vref at 80% */
1640 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1641 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1642 /* CD pin widget for input */
1643 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1644
1645 { }
1646};
1647
1648/*
1649 * 5-stack pin configuration:
1650 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1651 * line-in/side = 0x1a, f-mic = 0x1b
1652 */
1653static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1654 /*
1655 * preset connection lists of input pins
1656 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1657 */
1658 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1659 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1660
1661 /*
1662 * Set pin mode and muting
1663 */
1664 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001665 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1666 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1667 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1668 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001669 /* unmute pins for output (no gain on this amp) */
1670 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1671 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1672 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1673 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001676 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001677 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1678 /* Mic2 (as headphone out) for HP output */
1679 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001680 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001681 /* Line In pin widget for input */
1682 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1683 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1684 /* Line2 (as front mic) pin widget for input and vref at 80% */
1685 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1686 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1687 /* CD pin widget for input */
1688 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 { }
1691};
1692
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001693/*
1694 * W810 pin configuration:
1695 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1696 */
1697static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 /* hphone/speaker input selector: front DAC */
1699 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1700
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001701 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1702 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1703 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1704 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1705 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1706 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1707
1708 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001709 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 { }
1712};
1713
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001714/*
1715 * Z71V pin configuration:
1716 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1717 */
1718static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001719 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001720 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001721 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001722 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001723
Takashi Iwai16ded522005-06-10 19:58:24 +02001724 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001725 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001726 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001727 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001728
1729 { }
1730};
1731
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001732/*
1733 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001734 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1735 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001736 */
1737static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1738 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1739
Takashi Iwai16ded522005-06-10 19:58:24 +02001740 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001741 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001742 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001743 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001744 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001745 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001746 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001747 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1748
Takashi Iwai16ded522005-06-10 19:58:24 +02001749 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001750 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001751 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001753 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001754 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001755 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001756 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001757 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1758
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001759 { }
1760};
Takashi Iwai16ded522005-06-10 19:58:24 +02001761
Kailang Yangccc656c2006-10-17 12:32:26 +02001762/*
1763 * Uniwill pin configuration:
1764 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1765 * line = 0x1a
1766 */
1767static struct hda_verb alc880_uniwill_init_verbs[] = {
1768 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1769
1770 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1771 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1772 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1773 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1774 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1775 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1776 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1777 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1778 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1779 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1780 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1781 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1782 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1783 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1784
1785 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1786 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1787 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1788 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1789 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1790 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1791 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1792 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1793 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1794
1795 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1796 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1797
1798 { }
1799};
1800
1801/*
1802* Uniwill P53
1803* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1804 */
1805static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1806 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1807
1808 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1809 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1810 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1811 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1812 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1813 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1814 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1815 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1816 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1817 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1818 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1819 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1820
1821 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1822 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1823 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1824 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1825 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1826 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1827
1828 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1829 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1830
1831 { }
1832};
1833
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001834static struct hda_verb alc880_beep_init_verbs[] = {
1835 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1836 { }
1837};
1838
Kailang Yangccc656c2006-10-17 12:32:26 +02001839/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001840static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001841{
1842 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001843 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001844
1845 present = snd_hda_codec_read(codec, 0x14, 0,
1846 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001847 bits = present ? HDA_AMP_MUTE : 0;
1848 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1849 HDA_AMP_MUTE, bits);
1850 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1851 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001852}
1853
1854/* auto-toggle front mic */
1855static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1856{
1857 unsigned int present;
1858 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001859
1860 present = snd_hda_codec_read(codec, 0x18, 0,
1861 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001862 bits = present ? HDA_AMP_MUTE : 0;
1863 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001864}
1865
1866static void alc880_uniwill_automute(struct hda_codec *codec)
1867{
1868 alc880_uniwill_hp_automute(codec);
1869 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001870}
1871
1872static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1873 unsigned int res)
1874{
1875 /* Looks like the unsol event is incompatible with the standard
1876 * definition. 4bit tag is placed at 28 bit!
1877 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001878 switch (res >> 28) {
1879 case ALC880_HP_EVENT:
1880 alc880_uniwill_hp_automute(codec);
1881 break;
1882 case ALC880_MIC_EVENT:
1883 alc880_uniwill_mic_automute(codec);
1884 break;
1885 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001886}
1887
1888static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1889{
1890 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001891 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001892
1893 present = snd_hda_codec_read(codec, 0x14, 0,
1894 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001895 bits = present ? HDA_AMP_MUTE : 0;
1896 snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001897}
1898
1899static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1900{
1901 unsigned int present;
1902
1903 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001904 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1905 present &= HDA_AMP_VOLMASK;
1906 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1907 HDA_AMP_VOLMASK, present);
1908 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1909 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001910}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001911
Kailang Yangccc656c2006-10-17 12:32:26 +02001912static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1913 unsigned int res)
1914{
1915 /* Looks like the unsol event is incompatible with the standard
1916 * definition. 4bit tag is placed at 28 bit!
1917 */
1918 if ((res >> 28) == ALC880_HP_EVENT)
1919 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001920 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001921 alc880_uniwill_p53_dcvol_automute(codec);
1922}
1923
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001924/*
1925 * F1734 pin configuration:
1926 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1927 */
1928static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1929 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1930 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1931 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1932 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1933
1934 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1935 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1936 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1937 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1938
1939 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1940 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1941 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1942 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1943 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1944 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1945 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1946 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1947 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001948
Takashi Iwai937b4162008-02-11 14:52:36 +01001949 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
1950 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
1951
Takashi Iwai16ded522005-06-10 19:58:24 +02001952 { }
1953};
1954
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001955/*
1956 * ASUS pin configuration:
1957 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1958 */
1959static struct hda_verb alc880_pin_asus_init_verbs[] = {
1960 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1961 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1962 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1963 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1964
1965 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1966 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1967 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1968 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1969 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1971 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1972 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1973
1974 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1976 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1977 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1978 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1979 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1980 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1981 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1982 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1983
1984 { }
1985};
1986
1987/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001988#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1989#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001990
Kailang Yangdf694da2005-12-05 19:42:22 +01001991/* Clevo m520g init */
1992static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1993 /* headphone output */
1994 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1995 /* line-out */
1996 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1997 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1998 /* Line-in */
1999 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2000 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2001 /* CD */
2002 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2003 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2004 /* Mic1 (rear panel) */
2005 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2006 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2007 /* Mic2 (front panel) */
2008 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2009 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2010 /* headphone */
2011 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2012 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2013 /* change to EAPD mode */
2014 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2015 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2016
2017 { }
2018};
2019
2020static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002021 /* change to EAPD mode */
2022 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2023 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2024
Kailang Yangdf694da2005-12-05 19:42:22 +01002025 /* Headphone output */
2026 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2027 /* Front output*/
2028 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2029 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2030
2031 /* Line In pin widget for input */
2032 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2033 /* CD pin widget for input */
2034 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2035 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2036 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2037
2038 /* change to EAPD mode */
2039 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2040 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2041
2042 { }
2043};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002044
2045/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002046 * LG m1 express dual
2047 *
2048 * Pin assignment:
2049 * Rear Line-In/Out (blue): 0x14
2050 * Build-in Mic-In: 0x15
2051 * Speaker-out: 0x17
2052 * HP-Out (green): 0x1b
2053 * Mic-In/Out (red): 0x19
2054 * SPDIF-Out: 0x1e
2055 */
2056
2057/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2058static hda_nid_t alc880_lg_dac_nids[3] = {
2059 0x05, 0x02, 0x03
2060};
2061
2062/* seems analog CD is not working */
2063static struct hda_input_mux alc880_lg_capture_source = {
2064 .num_items = 3,
2065 .items = {
2066 { "Mic", 0x1 },
2067 { "Line", 0x5 },
2068 { "Internal Mic", 0x6 },
2069 },
2070};
2071
2072/* 2,4,6 channel modes */
2073static struct hda_verb alc880_lg_ch2_init[] = {
2074 /* set line-in and mic-in to input */
2075 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2076 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2077 { }
2078};
2079
2080static struct hda_verb alc880_lg_ch4_init[] = {
2081 /* set line-in to out and mic-in to input */
2082 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2083 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2084 { }
2085};
2086
2087static struct hda_verb alc880_lg_ch6_init[] = {
2088 /* set line-in and mic-in to output */
2089 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2090 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2091 { }
2092};
2093
2094static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2095 { 2, alc880_lg_ch2_init },
2096 { 4, alc880_lg_ch4_init },
2097 { 6, alc880_lg_ch6_init },
2098};
2099
2100static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002101 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2102 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002103 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2104 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2105 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2106 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2107 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2108 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2109 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2110 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2111 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2112 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2113 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2114 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2115 {
2116 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2117 .name = "Channel Mode",
2118 .info = alc_ch_mode_info,
2119 .get = alc_ch_mode_get,
2120 .put = alc_ch_mode_put,
2121 },
2122 { } /* end */
2123};
2124
2125static struct hda_verb alc880_lg_init_verbs[] = {
2126 /* set capture source to mic-in */
2127 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2128 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2129 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2130 /* mute all amp mixer inputs */
2131 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002132 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2133 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002134 /* line-in to input */
2135 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2136 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2137 /* built-in mic */
2138 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2139 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2140 /* speaker-out */
2141 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2142 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2143 /* mic-in to input */
2144 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2145 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2146 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2147 /* HP-out */
2148 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2149 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2150 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2151 /* jack sense */
2152 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2153 { }
2154};
2155
2156/* toggle speaker-output according to the hp-jack state */
2157static void alc880_lg_automute(struct hda_codec *codec)
2158{
2159 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002160 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002161
2162 present = snd_hda_codec_read(codec, 0x1b, 0,
2163 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002164 bits = present ? HDA_AMP_MUTE : 0;
2165 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2166 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002167}
2168
2169static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2170{
2171 /* Looks like the unsol event is incompatible with the standard
2172 * definition. 4bit tag is placed at 28 bit!
2173 */
2174 if ((res >> 28) == 0x01)
2175 alc880_lg_automute(codec);
2176}
2177
2178/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002179 * LG LW20
2180 *
2181 * Pin assignment:
2182 * Speaker-out: 0x14
2183 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002184 * Built-in Mic-In: 0x19
2185 * Line-In: 0x1b
2186 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002187 * SPDIF-Out: 0x1e
2188 */
2189
Takashi Iwaid6815182006-03-23 16:06:23 +01002190static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002191 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002192 .items = {
2193 { "Mic", 0x0 },
2194 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002195 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002196 },
2197};
2198
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002199#define alc880_lg_lw_modes alc880_threestack_modes
2200
Takashi Iwaid6815182006-03-23 16:06:23 +01002201static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002202 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2203 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2204 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2205 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2206 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2207 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2208 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2209 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2210 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2211 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002212 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2213 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2214 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2215 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002216 {
2217 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2218 .name = "Channel Mode",
2219 .info = alc_ch_mode_info,
2220 .get = alc_ch_mode_get,
2221 .put = alc_ch_mode_put,
2222 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002223 { } /* end */
2224};
2225
2226static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002227 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2228 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2229 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2230
Takashi Iwaid6815182006-03-23 16:06:23 +01002231 /* set capture source to mic-in */
2232 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2233 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2234 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002235 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002236 /* speaker-out */
2237 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2238 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2239 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002240 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2241 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2242 /* mic-in to input */
2243 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2244 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2245 /* built-in mic */
2246 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2247 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2248 /* jack sense */
2249 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2250 { }
2251};
2252
2253/* toggle speaker-output according to the hp-jack state */
2254static void alc880_lg_lw_automute(struct hda_codec *codec)
2255{
2256 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002257 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002258
2259 present = snd_hda_codec_read(codec, 0x1b, 0,
2260 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002261 bits = present ? HDA_AMP_MUTE : 0;
2262 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2263 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002264}
2265
2266static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2267{
2268 /* Looks like the unsol event is incompatible with the standard
2269 * definition. 4bit tag is placed at 28 bit!
2270 */
2271 if ((res >> 28) == 0x01)
2272 alc880_lg_lw_automute(codec);
2273}
2274
Takashi Iwaicb53c622007-08-10 17:21:45 +02002275#ifdef CONFIG_SND_HDA_POWER_SAVE
2276static struct hda_amp_list alc880_loopbacks[] = {
2277 { 0x0b, HDA_INPUT, 0 },
2278 { 0x0b, HDA_INPUT, 1 },
2279 { 0x0b, HDA_INPUT, 2 },
2280 { 0x0b, HDA_INPUT, 3 },
2281 { 0x0b, HDA_INPUT, 4 },
2282 { } /* end */
2283};
2284
2285static struct hda_amp_list alc880_lg_loopbacks[] = {
2286 { 0x0b, HDA_INPUT, 1 },
2287 { 0x0b, HDA_INPUT, 6 },
2288 { 0x0b, HDA_INPUT, 7 },
2289 { } /* end */
2290};
2291#endif
2292
Takashi Iwaid6815182006-03-23 16:06:23 +01002293/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002294 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002295 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297static int alc_init(struct hda_codec *codec)
2298{
2299 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002300 unsigned int i;
2301
2302 for (i = 0; i < spec->num_init_verbs; i++)
2303 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002304
2305 if (spec->init_hook)
2306 spec->init_hook(codec);
2307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 return 0;
2309}
2310
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002311static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2312{
2313 struct alc_spec *spec = codec->spec;
2314
2315 if (spec->unsol_event)
2316 spec->unsol_event(codec, res);
2317}
2318
Takashi Iwaicb53c622007-08-10 17:21:45 +02002319#ifdef CONFIG_SND_HDA_POWER_SAVE
2320static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2321{
2322 struct alc_spec *spec = codec->spec;
2323 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2324}
2325#endif
2326
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327/*
2328 * Analog playback callbacks
2329 */
2330static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2331 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002332 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333{
2334 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002335 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2336 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337}
2338
2339static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2340 struct hda_codec *codec,
2341 unsigned int stream_tag,
2342 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002343 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344{
2345 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002346 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2347 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348}
2349
2350static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2351 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002352 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353{
2354 struct alc_spec *spec = codec->spec;
2355 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2356}
2357
2358/*
2359 * Digital out
2360 */
2361static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2362 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002363 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364{
2365 struct alc_spec *spec = codec->spec;
2366 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2367}
2368
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002369static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2370 struct hda_codec *codec,
2371 unsigned int stream_tag,
2372 unsigned int format,
2373 struct snd_pcm_substream *substream)
2374{
2375 struct alc_spec *spec = codec->spec;
2376 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2377 stream_tag, format, substream);
2378}
2379
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2381 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002382 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383{
2384 struct alc_spec *spec = codec->spec;
2385 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2386}
2387
2388/*
2389 * Analog capture
2390 */
Takashi Iwai63300792008-01-24 15:31:36 +01002391static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 struct hda_codec *codec,
2393 unsigned int stream_tag,
2394 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002395 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396{
2397 struct alc_spec *spec = codec->spec;
2398
Takashi Iwai63300792008-01-24 15:31:36 +01002399 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 stream_tag, 0, format);
2401 return 0;
2402}
2403
Takashi Iwai63300792008-01-24 15:31:36 +01002404static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002406 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
2408 struct alc_spec *spec = codec->spec;
2409
Takashi Iwai63300792008-01-24 15:31:36 +01002410 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002411 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 return 0;
2413}
2414
2415
2416/*
2417 */
2418static struct hda_pcm_stream alc880_pcm_analog_playback = {
2419 .substreams = 1,
2420 .channels_min = 2,
2421 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002422 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 .ops = {
2424 .open = alc880_playback_pcm_open,
2425 .prepare = alc880_playback_pcm_prepare,
2426 .cleanup = alc880_playback_pcm_cleanup
2427 },
2428};
2429
2430static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002431 .substreams = 1,
2432 .channels_min = 2,
2433 .channels_max = 2,
2434 /* NID is set in alc_build_pcms */
2435};
2436
2437static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2438 .substreams = 1,
2439 .channels_min = 2,
2440 .channels_max = 2,
2441 /* NID is set in alc_build_pcms */
2442};
2443
2444static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2445 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 .channels_min = 2,
2447 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002448 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002450 .prepare = alc880_alt_capture_pcm_prepare,
2451 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 },
2453};
2454
2455static struct hda_pcm_stream alc880_pcm_digital_playback = {
2456 .substreams = 1,
2457 .channels_min = 2,
2458 .channels_max = 2,
2459 /* NID is set in alc_build_pcms */
2460 .ops = {
2461 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002462 .close = alc880_dig_playback_pcm_close,
2463 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 },
2465};
2466
2467static struct hda_pcm_stream alc880_pcm_digital_capture = {
2468 .substreams = 1,
2469 .channels_min = 2,
2470 .channels_max = 2,
2471 /* NID is set in alc_build_pcms */
2472};
2473
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002474/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002475static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002476 .substreams = 0,
2477 .channels_min = 0,
2478 .channels_max = 0,
2479};
2480
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481static int alc_build_pcms(struct hda_codec *codec)
2482{
2483 struct alc_spec *spec = codec->spec;
2484 struct hda_pcm *info = spec->pcm_rec;
2485 int i;
2486
2487 codec->num_pcms = 1;
2488 codec->pcm_info = info;
2489
2490 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002491 if (spec->stream_analog_playback) {
2492 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2493 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2494 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2495 }
2496 if (spec->stream_analog_capture) {
2497 snd_assert(spec->adc_nids, return -EINVAL);
2498 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2499 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
Takashi Iwai4a471b72005-12-07 13:56:29 +01002502 if (spec->channel_mode) {
2503 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2504 for (i = 0; i < spec->num_channel_mode; i++) {
2505 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2506 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 }
2509 }
2510
Takashi Iwaie08a0072006-09-07 17:52:14 +02002511 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002513 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002514 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002516 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002517 if (spec->multiout.dig_out_nid &&
2518 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2520 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2521 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002522 if (spec->dig_in_nid &&
2523 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2525 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2526 }
2527 }
2528
Takashi Iwaie08a0072006-09-07 17:52:14 +02002529 /* If the use of more than one ADC is requested for the current
2530 * model, configure a second analog capture-only PCM.
2531 */
2532 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002533 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2534 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002535 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002536 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002537 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002538 if (spec->alt_dac_nid) {
2539 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2540 *spec->stream_analog_alt_playback;
2541 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2542 spec->alt_dac_nid;
2543 } else {
2544 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2545 alc_pcm_null_stream;
2546 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2547 }
2548 if (spec->num_adc_nids > 1) {
2549 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2550 *spec->stream_analog_alt_capture;
2551 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2552 spec->adc_nids[1];
2553 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2554 spec->num_adc_nids - 1;
2555 } else {
2556 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2557 alc_pcm_null_stream;
2558 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002559 }
2560 }
2561
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 return 0;
2563}
2564
2565static void alc_free(struct hda_codec *codec)
2566{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002567 struct alc_spec *spec = codec->spec;
2568 unsigned int i;
2569
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002570 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002571 return;
2572
2573 if (spec->kctl_alloc) {
2574 for (i = 0; i < spec->num_kctl_used; i++)
2575 kfree(spec->kctl_alloc[i].name);
2576 kfree(spec->kctl_alloc);
2577 }
2578 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579}
2580
2581/*
2582 */
2583static struct hda_codec_ops alc_patch_ops = {
2584 .build_controls = alc_build_controls,
2585 .build_pcms = alc_build_pcms,
2586 .init = alc_init,
2587 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002588 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002589#ifdef CONFIG_SND_HDA_POWER_SAVE
2590 .check_power_status = alc_check_power_status,
2591#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592};
2593
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002594
2595/*
2596 * Test configuration for debugging
2597 *
2598 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2599 * enum controls.
2600 */
2601#ifdef CONFIG_SND_DEBUG
2602static hda_nid_t alc880_test_dac_nids[4] = {
2603 0x02, 0x03, 0x04, 0x05
2604};
2605
2606static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002607 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002608 .items = {
2609 { "In-1", 0x0 },
2610 { "In-2", 0x1 },
2611 { "In-3", 0x2 },
2612 { "In-4", 0x3 },
2613 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002614 { "Front", 0x5 },
2615 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002616 },
2617};
2618
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002619static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002620 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002621 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002622 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002623 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002624};
2625
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002626static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2627 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002628{
2629 static char *texts[] = {
2630 "N/A", "Line Out", "HP Out",
2631 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2632 };
2633 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2634 uinfo->count = 1;
2635 uinfo->value.enumerated.items = 8;
2636 if (uinfo->value.enumerated.item >= 8)
2637 uinfo->value.enumerated.item = 7;
2638 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2639 return 0;
2640}
2641
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002642static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2643 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002644{
2645 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2646 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2647 unsigned int pin_ctl, item = 0;
2648
2649 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2650 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2651 if (pin_ctl & AC_PINCTL_OUT_EN) {
2652 if (pin_ctl & AC_PINCTL_HP_EN)
2653 item = 2;
2654 else
2655 item = 1;
2656 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2657 switch (pin_ctl & AC_PINCTL_VREFEN) {
2658 case AC_PINCTL_VREF_HIZ: item = 3; break;
2659 case AC_PINCTL_VREF_50: item = 4; break;
2660 case AC_PINCTL_VREF_GRD: item = 5; break;
2661 case AC_PINCTL_VREF_80: item = 6; break;
2662 case AC_PINCTL_VREF_100: item = 7; break;
2663 }
2664 }
2665 ucontrol->value.enumerated.item[0] = item;
2666 return 0;
2667}
2668
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002669static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2670 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002671{
2672 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2673 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2674 static unsigned int ctls[] = {
2675 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2676 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2677 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2678 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2679 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2680 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2681 };
2682 unsigned int old_ctl, new_ctl;
2683
2684 old_ctl = snd_hda_codec_read(codec, nid, 0,
2685 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2686 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2687 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002688 int val;
2689 snd_hda_codec_write_cache(codec, nid, 0,
2690 AC_VERB_SET_PIN_WIDGET_CONTROL,
2691 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002692 val = ucontrol->value.enumerated.item[0] >= 3 ?
2693 HDA_AMP_MUTE : 0;
2694 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2695 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002696 return 1;
2697 }
2698 return 0;
2699}
2700
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002701static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2702 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002703{
2704 static char *texts[] = {
2705 "Front", "Surround", "CLFE", "Side"
2706 };
2707 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2708 uinfo->count = 1;
2709 uinfo->value.enumerated.items = 4;
2710 if (uinfo->value.enumerated.item >= 4)
2711 uinfo->value.enumerated.item = 3;
2712 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2713 return 0;
2714}
2715
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002716static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2717 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002718{
2719 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2720 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2721 unsigned int sel;
2722
2723 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2724 ucontrol->value.enumerated.item[0] = sel & 3;
2725 return 0;
2726}
2727
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002728static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2729 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002730{
2731 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2732 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2733 unsigned int sel;
2734
2735 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2736 if (ucontrol->value.enumerated.item[0] != sel) {
2737 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002738 snd_hda_codec_write_cache(codec, nid, 0,
2739 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002740 return 1;
2741 }
2742 return 0;
2743}
2744
2745#define PIN_CTL_TEST(xname,nid) { \
2746 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2747 .name = xname, \
2748 .info = alc_test_pin_ctl_info, \
2749 .get = alc_test_pin_ctl_get, \
2750 .put = alc_test_pin_ctl_put, \
2751 .private_value = nid \
2752 }
2753
2754#define PIN_SRC_TEST(xname,nid) { \
2755 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2756 .name = xname, \
2757 .info = alc_test_pin_src_info, \
2758 .get = alc_test_pin_src_get, \
2759 .put = alc_test_pin_src_put, \
2760 .private_value = nid \
2761 }
2762
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002763static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002764 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2765 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2766 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2767 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002768 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2769 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2770 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2771 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002772 PIN_CTL_TEST("Front Pin Mode", 0x14),
2773 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2774 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2775 PIN_CTL_TEST("Side Pin Mode", 0x17),
2776 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2777 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2778 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2779 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2780 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2781 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2782 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2783 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2784 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2785 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2786 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2787 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2788 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2789 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2790 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2791 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2792 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2793 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002794 {
2795 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2796 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002797 .info = alc_ch_mode_info,
2798 .get = alc_ch_mode_get,
2799 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002800 },
2801 { } /* end */
2802};
2803
2804static struct hda_verb alc880_test_init_verbs[] = {
2805 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002806 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2808 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2809 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2810 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2811 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2812 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2813 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002814 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002815 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2816 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2817 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2818 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002819 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002820 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2821 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2822 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2823 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002824 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002825 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2826 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2827 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2828 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002829 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002830 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2831 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002832 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2833 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2834 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002835 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002836 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2837 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2838 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2839 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002840 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002841 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002842 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002843 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002844 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002845 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002846 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002847 /* Analog input/passthru */
2848 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2849 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2850 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2851 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2852 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002853 { }
2854};
2855#endif
2856
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857/*
2858 */
2859
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002860static const char *alc880_models[ALC880_MODEL_LAST] = {
2861 [ALC880_3ST] = "3stack",
2862 [ALC880_TCL_S700] = "tcl",
2863 [ALC880_3ST_DIG] = "3stack-digout",
2864 [ALC880_CLEVO] = "clevo",
2865 [ALC880_5ST] = "5stack",
2866 [ALC880_5ST_DIG] = "5stack-digout",
2867 [ALC880_W810] = "w810",
2868 [ALC880_Z71V] = "z71v",
2869 [ALC880_6ST] = "6stack",
2870 [ALC880_6ST_DIG] = "6stack-digout",
2871 [ALC880_ASUS] = "asus",
2872 [ALC880_ASUS_W1V] = "asus-w1v",
2873 [ALC880_ASUS_DIG] = "asus-dig",
2874 [ALC880_ASUS_DIG2] = "asus-dig2",
2875 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002876 [ALC880_UNIWILL_P53] = "uniwill-p53",
2877 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002878 [ALC880_F1734] = "F1734",
2879 [ALC880_LG] = "lg",
2880 [ALC880_LG_LW] = "lg-lw",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002881#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002882 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002883#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002884 [ALC880_AUTO] = "auto",
2885};
2886
2887static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002888 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002889 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2890 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2891 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2892 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2893 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2894 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2895 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2896 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002897 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2898 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002899 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2900 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2901 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2902 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2903 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2904 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2905 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2906 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2907 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2908 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Tobin Davis0e4ceb72007-01-08 10:54:26 +01002909 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002910 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2911 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2912 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002913 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002914 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002915 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2916 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002917 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2918 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002919 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2920 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2921 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2922 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002923 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2924 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002925 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002926 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002927 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002928 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002929 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2930 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002931 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2932 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002933 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002934 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002935 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002936 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002937 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002938 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2939 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002940 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002941 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2942 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
2943 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2944 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002945 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2946 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002947 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002948 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002949 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2950 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002951 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2952 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2953 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002954 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
2955 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2956 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 {}
2958};
2959
Takashi Iwai16ded522005-06-10 19:58:24 +02002960/*
Kailang Yangdf694da2005-12-05 19:42:22 +01002961 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02002962 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002963static struct alc_config_preset alc880_presets[] = {
2964 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002965 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002966 .init_verbs = { alc880_volume_init_verbs,
2967 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002968 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002969 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002970 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2971 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002972 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002973 .input_mux = &alc880_capture_source,
2974 },
2975 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002976 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002977 .init_verbs = { alc880_volume_init_verbs,
2978 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002979 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002980 .dac_nids = alc880_dac_nids,
2981 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002982 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2983 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002984 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002985 .input_mux = &alc880_capture_source,
2986 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002987 [ALC880_TCL_S700] = {
2988 .mixers = { alc880_tcl_s700_mixer },
2989 .init_verbs = { alc880_volume_init_verbs,
2990 alc880_pin_tcl_S700_init_verbs,
2991 alc880_gpio2_init_verbs },
2992 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2993 .dac_nids = alc880_dac_nids,
2994 .hp_nid = 0x03,
2995 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2996 .channel_mode = alc880_2_jack_modes,
2997 .input_mux = &alc880_capture_source,
2998 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002999 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003000 .mixers = { alc880_three_stack_mixer,
3001 alc880_five_stack_mixer},
3002 .init_verbs = { alc880_volume_init_verbs,
3003 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003004 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3005 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003006 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3007 .channel_mode = alc880_fivestack_modes,
3008 .input_mux = &alc880_capture_source,
3009 },
3010 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003011 .mixers = { alc880_three_stack_mixer,
3012 alc880_five_stack_mixer },
3013 .init_verbs = { alc880_volume_init_verbs,
3014 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003015 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3016 .dac_nids = alc880_dac_nids,
3017 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003018 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3019 .channel_mode = alc880_fivestack_modes,
3020 .input_mux = &alc880_capture_source,
3021 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003022 [ALC880_6ST] = {
3023 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003024 .init_verbs = { alc880_volume_init_verbs,
3025 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003026 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3027 .dac_nids = alc880_6st_dac_nids,
3028 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3029 .channel_mode = alc880_sixstack_modes,
3030 .input_mux = &alc880_6stack_capture_source,
3031 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003032 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003033 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003034 .init_verbs = { alc880_volume_init_verbs,
3035 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003036 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3037 .dac_nids = alc880_6st_dac_nids,
3038 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003039 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3040 .channel_mode = alc880_sixstack_modes,
3041 .input_mux = &alc880_6stack_capture_source,
3042 },
3043 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003044 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003045 .init_verbs = { alc880_volume_init_verbs,
3046 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003047 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003048 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3049 .dac_nids = alc880_w810_dac_nids,
3050 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003051 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3052 .channel_mode = alc880_w810_modes,
3053 .input_mux = &alc880_capture_source,
3054 },
3055 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003056 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003057 .init_verbs = { alc880_volume_init_verbs,
3058 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003059 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3060 .dac_nids = alc880_z71v_dac_nids,
3061 .dig_out_nid = ALC880_DIGOUT_NID,
3062 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003063 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3064 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003065 .input_mux = &alc880_capture_source,
3066 },
3067 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003068 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003069 .init_verbs = { alc880_volume_init_verbs,
3070 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003071 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3072 .dac_nids = alc880_f1734_dac_nids,
3073 .hp_nid = 0x02,
3074 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3075 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003076 .input_mux = &alc880_f1734_capture_source,
3077 .unsol_event = alc880_uniwill_p53_unsol_event,
3078 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003079 },
3080 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003081 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003082 .init_verbs = { alc880_volume_init_verbs,
3083 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003084 alc880_gpio1_init_verbs },
3085 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3086 .dac_nids = alc880_asus_dac_nids,
3087 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3088 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003089 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003090 .input_mux = &alc880_capture_source,
3091 },
3092 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003093 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003094 .init_verbs = { alc880_volume_init_verbs,
3095 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003096 alc880_gpio1_init_verbs },
3097 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3098 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003099 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003100 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3101 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003102 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003103 .input_mux = &alc880_capture_source,
3104 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003105 [ALC880_ASUS_DIG2] = {
3106 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003107 .init_verbs = { alc880_volume_init_verbs,
3108 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003109 alc880_gpio2_init_verbs }, /* use GPIO2 */
3110 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3111 .dac_nids = alc880_asus_dac_nids,
3112 .dig_out_nid = ALC880_DIGOUT_NID,
3113 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3114 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003115 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003116 .input_mux = &alc880_capture_source,
3117 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003118 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003119 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003120 .init_verbs = { alc880_volume_init_verbs,
3121 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003122 alc880_gpio1_init_verbs },
3123 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3124 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003125 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003126 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3127 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003128 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 .input_mux = &alc880_capture_source,
3130 },
3131 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003132 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003133 .init_verbs = { alc880_volume_init_verbs,
3134 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003135 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3136 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003137 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003138 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3139 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003140 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003141 .input_mux = &alc880_capture_source,
3142 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003143 [ALC880_UNIWILL] = {
3144 .mixers = { alc880_uniwill_mixer },
3145 .init_verbs = { alc880_volume_init_verbs,
3146 alc880_uniwill_init_verbs },
3147 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3148 .dac_nids = alc880_asus_dac_nids,
3149 .dig_out_nid = ALC880_DIGOUT_NID,
3150 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3151 .channel_mode = alc880_threestack_modes,
3152 .need_dac_fix = 1,
3153 .input_mux = &alc880_capture_source,
3154 .unsol_event = alc880_uniwill_unsol_event,
3155 .init_hook = alc880_uniwill_automute,
3156 },
3157 [ALC880_UNIWILL_P53] = {
3158 .mixers = { alc880_uniwill_p53_mixer },
3159 .init_verbs = { alc880_volume_init_verbs,
3160 alc880_uniwill_p53_init_verbs },
3161 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3162 .dac_nids = alc880_asus_dac_nids,
3163 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003164 .channel_mode = alc880_threestack_modes,
3165 .input_mux = &alc880_capture_source,
3166 .unsol_event = alc880_uniwill_p53_unsol_event,
3167 .init_hook = alc880_uniwill_p53_hp_automute,
3168 },
3169 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003170 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003171 alc880_pcbeep_mixer, },
3172 .init_verbs = { alc880_volume_init_verbs,
3173 alc880_uniwill_p53_init_verbs,
3174 alc880_beep_init_verbs },
3175 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3176 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003177 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003178 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3179 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003180 .input_mux = &alc880_capture_source,
3181 .unsol_event = alc880_uniwill_p53_unsol_event,
3182 .init_hook = alc880_uniwill_p53_hp_automute,
3183 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003184 [ALC880_CLEVO] = {
3185 .mixers = { alc880_three_stack_mixer },
3186 .init_verbs = { alc880_volume_init_verbs,
3187 alc880_pin_clevo_init_verbs },
3188 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3189 .dac_nids = alc880_dac_nids,
3190 .hp_nid = 0x03,
3191 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3192 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003193 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003194 .input_mux = &alc880_capture_source,
3195 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003196 [ALC880_LG] = {
3197 .mixers = { alc880_lg_mixer },
3198 .init_verbs = { alc880_volume_init_verbs,
3199 alc880_lg_init_verbs },
3200 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3201 .dac_nids = alc880_lg_dac_nids,
3202 .dig_out_nid = ALC880_DIGOUT_NID,
3203 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3204 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003205 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003206 .input_mux = &alc880_lg_capture_source,
3207 .unsol_event = alc880_lg_unsol_event,
3208 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003209#ifdef CONFIG_SND_HDA_POWER_SAVE
3210 .loopbacks = alc880_lg_loopbacks,
3211#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003212 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003213 [ALC880_LG_LW] = {
3214 .mixers = { alc880_lg_lw_mixer },
3215 .init_verbs = { alc880_volume_init_verbs,
3216 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003217 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003218 .dac_nids = alc880_dac_nids,
3219 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003220 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3221 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003222 .input_mux = &alc880_lg_lw_capture_source,
3223 .unsol_event = alc880_lg_lw_unsol_event,
3224 .init_hook = alc880_lg_lw_automute,
3225 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003226#ifdef CONFIG_SND_DEBUG
3227 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003228 .mixers = { alc880_test_mixer },
3229 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003230 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3231 .dac_nids = alc880_test_dac_nids,
3232 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003233 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3234 .channel_mode = alc880_test_modes,
3235 .input_mux = &alc880_test_capture_source,
3236 },
3237#endif
3238};
3239
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003240/*
3241 * Automatic parse of I/O pins from the BIOS configuration
3242 */
3243
3244#define NUM_CONTROL_ALLOC 32
3245#define NUM_VERB_ALLOC 32
3246
3247enum {
3248 ALC_CTL_WIDGET_VOL,
3249 ALC_CTL_WIDGET_MUTE,
3250 ALC_CTL_BIND_MUTE,
3251};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003252static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003253 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3254 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003255 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003256};
3257
3258/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003259static int add_control(struct alc_spec *spec, int type, const char *name,
3260 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003261{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003262 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003263
3264 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3265 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3266
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003267 /* array + terminator */
3268 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3269 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003270 return -ENOMEM;
3271 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003272 memcpy(knew, spec->kctl_alloc,
3273 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003274 kfree(spec->kctl_alloc);
3275 }
3276 spec->kctl_alloc = knew;
3277 spec->num_kctl_alloc = num;
3278 }
3279
3280 knew = &spec->kctl_alloc[spec->num_kctl_used];
3281 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003282 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003283 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003284 return -ENOMEM;
3285 knew->private_value = val;
3286 spec->num_kctl_used++;
3287 return 0;
3288}
3289
3290#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3291#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3292#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3293#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3294#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3295#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3296#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3297#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3298#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3299#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3300#define ALC880_PIN_CD_NID 0x1c
3301
3302/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003303static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3304 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003305{
3306 hda_nid_t nid;
3307 int assigned[4];
3308 int i, j;
3309
3310 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003311 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003312
3313 /* check the pins hardwired to audio widget */
3314 for (i = 0; i < cfg->line_outs; i++) {
3315 nid = cfg->line_out_pins[i];
3316 if (alc880_is_fixed_pin(nid)) {
3317 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003318 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003319 assigned[idx] = 1;
3320 }
3321 }
3322 /* left pins can be connect to any audio widget */
3323 for (i = 0; i < cfg->line_outs; i++) {
3324 nid = cfg->line_out_pins[i];
3325 if (alc880_is_fixed_pin(nid))
3326 continue;
3327 /* search for an empty channel */
3328 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003329 if (!assigned[j]) {
3330 spec->multiout.dac_nids[i] =
3331 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003332 assigned[j] = 1;
3333 break;
3334 }
3335 }
3336 }
3337 spec->multiout.num_dacs = cfg->line_outs;
3338 return 0;
3339}
3340
3341/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003342static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3343 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003344{
3345 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003346 static const char *chname[4] = {
3347 "Front", "Surround", NULL /*CLFE*/, "Side"
3348 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003349 hda_nid_t nid;
3350 int i, err;
3351
3352 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003353 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003354 continue;
3355 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3356 if (i == 2) {
3357 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003358 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3359 "Center Playback Volume",
3360 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3361 HDA_OUTPUT));
3362 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003363 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003364 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3365 "LFE Playback Volume",
3366 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3367 HDA_OUTPUT));
3368 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003369 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003370 err = add_control(spec, ALC_CTL_BIND_MUTE,
3371 "Center Playback Switch",
3372 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3373 HDA_INPUT));
3374 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003375 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003376 err = add_control(spec, ALC_CTL_BIND_MUTE,
3377 "LFE Playback Switch",
3378 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3379 HDA_INPUT));
3380 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003381 return err;
3382 } else {
3383 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003384 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3385 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3386 HDA_OUTPUT));
3387 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003388 return err;
3389 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003390 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3391 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3392 HDA_INPUT));
3393 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003394 return err;
3395 }
3396 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003397 return 0;
3398}
3399
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003400/* add playback controls for speaker and HP outputs */
3401static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3402 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003403{
3404 hda_nid_t nid;
3405 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003406 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003407
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003408 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003409 return 0;
3410
3411 if (alc880_is_fixed_pin(pin)) {
3412 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003413 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003414 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003415 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003416 else
3417 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003418 /* control HP volume/switch on the output mixer amp */
3419 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003420 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003421 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3422 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3423 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424 return err;
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_BIND_MUTE, name,
3427 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3428 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003429 return err;
3430 } else if (alc880_is_multi_pin(pin)) {
3431 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003432 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003433 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003434 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3435 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3436 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003437 return err;
3438 }
3439 return 0;
3440}
3441
3442/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003443static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3444 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003445 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003446{
3447 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003448 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003449
3450 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003451 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3452 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3453 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003454 return err;
3455 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003456 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3457 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3458 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003459 return err;
3460 return 0;
3461}
3462
3463/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003464static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3465 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003466{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003467 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003468 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003469
3470 for (i = 0; i < AUTO_PIN_LAST; i++) {
3471 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003472 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003473 err = new_analog_input(spec, cfg->input_pins[i],
3474 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003475 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003476 if (err < 0)
3477 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003478 imux->items[imux->num_items].label =
3479 auto_pin_cfg_labels[i];
3480 imux->items[imux->num_items].index =
3481 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003482 imux->num_items++;
3483 }
3484 }
3485 return 0;
3486}
3487
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003488static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3489 unsigned int pin_type)
3490{
3491 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3492 pin_type);
3493 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003494 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3495 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003496}
3497
Kailang Yangdf694da2005-12-05 19:42:22 +01003498static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3499 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003500 int dac_idx)
3501{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003502 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003503 /* need the manual connection? */
3504 if (alc880_is_multi_pin(nid)) {
3505 struct alc_spec *spec = codec->spec;
3506 int idx = alc880_multi_pin_idx(nid);
3507 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3508 AC_VERB_SET_CONNECT_SEL,
3509 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3510 }
3511}
3512
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003513static int get_pin_type(int line_out_type)
3514{
3515 if (line_out_type == AUTO_PIN_HP_OUT)
3516 return PIN_HP;
3517 else
3518 return PIN_OUT;
3519}
3520
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003521static void alc880_auto_init_multi_out(struct hda_codec *codec)
3522{
3523 struct alc_spec *spec = codec->spec;
3524 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003525
3526 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003527 for (i = 0; i < spec->autocfg.line_outs; i++) {
3528 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003529 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3530 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003531 }
3532}
3533
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003534static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003535{
3536 struct alc_spec *spec = codec->spec;
3537 hda_nid_t pin;
3538
Takashi Iwai82bc9552006-03-21 11:24:42 +01003539 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003540 if (pin) /* connect to front */
3541 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003542 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003543 if (pin) /* connect to front */
3544 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3545}
3546
3547static void alc880_auto_init_analog_input(struct hda_codec *codec)
3548{
3549 struct alc_spec *spec = codec->spec;
3550 int i;
3551
3552 for (i = 0; i < AUTO_PIN_LAST; i++) {
3553 hda_nid_t nid = spec->autocfg.input_pins[i];
3554 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003555 snd_hda_codec_write(codec, nid, 0,
3556 AC_VERB_SET_PIN_WIDGET_CONTROL,
3557 i <= AUTO_PIN_FRONT_MIC ?
3558 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003559 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003560 snd_hda_codec_write(codec, nid, 0,
3561 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003562 AMP_OUT_MUTE);
3563 }
3564 }
3565}
3566
3567/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003568/* return 1 if successful, 0 if the proper config is not found,
3569 * or a negative error code
3570 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003571static int alc880_parse_auto_config(struct hda_codec *codec)
3572{
3573 struct alc_spec *spec = codec->spec;
3574 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003575 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003576
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003577 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3578 alc880_ignore);
3579 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003580 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003581 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003582 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003583
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003584 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3585 if (err < 0)
3586 return err;
3587 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3588 if (err < 0)
3589 return err;
3590 err = alc880_auto_create_extra_out(spec,
3591 spec->autocfg.speaker_pins[0],
3592 "Speaker");
3593 if (err < 0)
3594 return err;
3595 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3596 "Headphone");
3597 if (err < 0)
3598 return err;
3599 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3600 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003601 return err;
3602
3603 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3604
3605 if (spec->autocfg.dig_out_pin)
3606 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3607 if (spec->autocfg.dig_in_pin)
3608 spec->dig_in_nid = ALC880_DIGIN_NID;
3609
3610 if (spec->kctl_alloc)
3611 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3612
3613 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3614
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003615 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003616 spec->input_mux = &spec->private_imux;
3617
3618 return 1;
3619}
3620
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003621/* additional initialization for auto-configuration model */
3622static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003623{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003624 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003625 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003626 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003627 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003628 if (spec->unsol_event)
3629 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003630}
3631
3632/*
3633 * OK, here we have finally the patch for ALC880
3634 */
3635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636static int patch_alc880(struct hda_codec *codec)
3637{
3638 struct alc_spec *spec;
3639 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003640 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003642 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 if (spec == NULL)
3644 return -ENOMEM;
3645
3646 codec->spec = spec;
3647
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003648 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3649 alc880_models,
3650 alc880_cfg_tbl);
3651 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003652 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3653 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003654 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 }
3656
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003657 if (board_config == ALC880_AUTO) {
3658 /* automatic parse from the BIOS config */
3659 err = alc880_parse_auto_config(codec);
3660 if (err < 0) {
3661 alc_free(codec);
3662 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003663 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003664 printk(KERN_INFO
3665 "hda_codec: Cannot set up configuration "
3666 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003667 board_config = ALC880_3ST;
3668 }
3669 }
3670
Kailang Yangdf694da2005-12-05 19:42:22 +01003671 if (board_config != ALC880_AUTO)
3672 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673
3674 spec->stream_name_analog = "ALC880 Analog";
3675 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3676 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003677 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
3679 spec->stream_name_digital = "ALC880 Digital";
3680 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3681 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3682
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003683 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003684 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003685 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003686 /* get type */
3687 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003688 if (wcap != AC_WID_AUD_IN) {
3689 spec->adc_nids = alc880_adc_nids_alt;
3690 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003691 spec->mixers[spec->num_mixers] =
3692 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003693 spec->num_mixers++;
3694 } else {
3695 spec->adc_nids = alc880_adc_nids;
3696 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3697 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3698 spec->num_mixers++;
3699 }
3700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701
Takashi Iwai2134ea42008-01-10 16:53:55 +01003702 spec->vmaster_nid = 0x0c;
3703
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003705 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003706 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003707#ifdef CONFIG_SND_HDA_POWER_SAVE
3708 if (!spec->loopback.amplist)
3709 spec->loopback.amplist = alc880_loopbacks;
3710#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711
3712 return 0;
3713}
3714
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003715
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716/*
3717 * ALC260 support
3718 */
3719
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003720static hda_nid_t alc260_dac_nids[1] = {
3721 /* front */
3722 0x02,
3723};
3724
3725static hda_nid_t alc260_adc_nids[1] = {
3726 /* ADC0 */
3727 0x04,
3728};
3729
Kailang Yangdf694da2005-12-05 19:42:22 +01003730static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003731 /* ADC1 */
3732 0x05,
3733};
3734
Kailang Yangdf694da2005-12-05 19:42:22 +01003735static hda_nid_t alc260_hp_adc_nids[2] = {
3736 /* ADC1, 0 */
3737 0x05, 0x04
3738};
3739
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003740/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3741 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3742 */
3743static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003744 /* ADC0, ADC1 */
3745 0x04, 0x05
3746};
3747
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003748#define ALC260_DIGOUT_NID 0x03
3749#define ALC260_DIGIN_NID 0x06
3750
3751static struct hda_input_mux alc260_capture_source = {
3752 .num_items = 4,
3753 .items = {
3754 { "Mic", 0x0 },
3755 { "Front Mic", 0x1 },
3756 { "Line", 0x2 },
3757 { "CD", 0x4 },
3758 },
3759};
3760
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003761/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003762 * headphone jack and the internal CD lines since these are the only pins at
3763 * which audio can appear. For flexibility, also allow the option of
3764 * recording the mixer output on the second ADC (ADC0 doesn't have a
3765 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003766 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003767static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3768 {
3769 .num_items = 3,
3770 .items = {
3771 { "Mic/Line", 0x0 },
3772 { "CD", 0x4 },
3773 { "Headphone", 0x2 },
3774 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003775 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003776 {
3777 .num_items = 4,
3778 .items = {
3779 { "Mic/Line", 0x0 },
3780 { "CD", 0x4 },
3781 { "Headphone", 0x2 },
3782 { "Mixer", 0x5 },
3783 },
3784 },
3785
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003786};
3787
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003788/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3789 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003790 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003791static struct hda_input_mux alc260_acer_capture_sources[2] = {
3792 {
3793 .num_items = 4,
3794 .items = {
3795 { "Mic", 0x0 },
3796 { "Line", 0x2 },
3797 { "CD", 0x4 },
3798 { "Headphone", 0x5 },
3799 },
3800 },
3801 {
3802 .num_items = 5,
3803 .items = {
3804 { "Mic", 0x0 },
3805 { "Line", 0x2 },
3806 { "CD", 0x4 },
3807 { "Headphone", 0x6 },
3808 { "Mixer", 0x5 },
3809 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003810 },
3811};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812/*
3813 * This is just place-holder, so there's something for alc_build_pcms to look
3814 * at when it calculates the maximum number of channels. ALC260 has no mixer
3815 * element which allows changing the channel mode, so the verb list is
3816 * never used.
3817 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003818static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 { 2, NULL },
3820};
3821
Kailang Yangdf694da2005-12-05 19:42:22 +01003822
3823/* Mixer combinations
3824 *
3825 * basic: base_output + input + pc_beep + capture
3826 * HP: base_output + input + capture_alt
3827 * HP_3013: hp_3013 + input + capture
3828 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003829 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003830 */
3831
3832static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003833 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003834 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003835 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3836 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3837 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3838 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3839 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003840};
Kailang Yangdf694da2005-12-05 19:42:22 +01003841
3842static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3844 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3845 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3846 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3847 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3848 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3849 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3850 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 { } /* end */
3852};
3853
Kailang Yangdf694da2005-12-05 19:42:22 +01003854static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3855 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3856 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3857 { } /* end */
3858};
3859
Takashi Iwaibec15c32008-01-28 18:16:30 +01003860/* update HP, line and mono out pins according to the master switch */
3861static void alc260_hp_master_update(struct hda_codec *codec,
3862 hda_nid_t hp, hda_nid_t line,
3863 hda_nid_t mono)
3864{
3865 struct alc_spec *spec = codec->spec;
3866 unsigned int val = spec->master_sw ? PIN_HP : 0;
3867 /* change HP and line-out pins */
3868 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3869 val);
3870 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3871 val);
3872 /* mono (speaker) depending on the HP jack sense */
3873 val = (val && !spec->jack_present) ? PIN_OUT : 0;
3874 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3875 val);
3876}
3877
3878static int alc260_hp_master_sw_get(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 *ucontrol->value.integer.value = spec->master_sw;
3884 return 0;
3885}
3886
3887static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
3888 struct snd_ctl_elem_value *ucontrol)
3889{
3890 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3891 struct alc_spec *spec = codec->spec;
3892 int val = !!*ucontrol->value.integer.value;
3893 hda_nid_t hp, line, mono;
3894
3895 if (val == spec->master_sw)
3896 return 0;
3897 spec->master_sw = val;
3898 hp = (kcontrol->private_value >> 16) & 0xff;
3899 line = (kcontrol->private_value >> 8) & 0xff;
3900 mono = kcontrol->private_value & 0xff;
3901 alc260_hp_master_update(codec, hp, line, mono);
3902 return 1;
3903}
3904
3905static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
3906 {
3907 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3908 .name = "Master Playback Switch",
3909 .info = snd_ctl_boolean_mono_info,
3910 .get = alc260_hp_master_sw_get,
3911 .put = alc260_hp_master_sw_put,
3912 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
3913 },
3914 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3915 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
3916 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3917 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3918 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
3919 HDA_OUTPUT),
3920 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3921 { } /* end */
3922};
3923
3924static struct hda_verb alc260_hp_unsol_verbs[] = {
3925 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3926 {},
3927};
3928
3929static void alc260_hp_automute(struct hda_codec *codec)
3930{
3931 struct alc_spec *spec = codec->spec;
3932 unsigned int present;
3933
3934 present = snd_hda_codec_read(codec, 0x10, 0,
3935 AC_VERB_GET_PIN_SENSE, 0);
3936 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3937 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
3938}
3939
3940static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3941{
3942 if ((res >> 26) == ALC880_HP_EVENT)
3943 alc260_hp_automute(codec);
3944}
3945
Kailang Yangdf694da2005-12-05 19:42:22 +01003946static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01003947 {
3948 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3949 .name = "Master Playback Switch",
3950 .info = snd_ctl_boolean_mono_info,
3951 .get = alc260_hp_master_sw_get,
3952 .put = alc260_hp_master_sw_put,
3953 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
3954 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003955 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3956 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3957 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
3958 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
3959 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01003961 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3962 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003963 { } /* end */
3964};
3965
Takashi Iwaibec15c32008-01-28 18:16:30 +01003966static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
3967 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3968 {},
3969};
3970
3971static void alc260_hp_3013_automute(struct hda_codec *codec)
3972{
3973 struct alc_spec *spec = codec->spec;
3974 unsigned int present;
3975
3976 present = snd_hda_codec_read(codec, 0x15, 0,
3977 AC_VERB_GET_PIN_SENSE, 0);
3978 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3979 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
3980}
3981
3982static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
3983 unsigned int res)
3984{
3985 if ((res >> 26) == ALC880_HP_EVENT)
3986 alc260_hp_3013_automute(codec);
3987}
3988
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003989/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
3990 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
3991 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003992static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003993 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003994 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003995 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003996 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3997 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3998 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
3999 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004000 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004001 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4002 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004003 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4004 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004005 { } /* end */
4006};
4007
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004008/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4009 * versions of the ALC260 don't act on requests to enable mic bias from NID
4010 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4011 * datasheet doesn't mention this restriction. At this stage it's not clear
4012 * whether this behaviour is intentional or is a hardware bug in chip
4013 * revisions available in early 2006. Therefore for now allow the
4014 * "Headphone Jack Mode" control to span all choices, but if it turns out
4015 * that the lack of mic bias for this NID is intentional we could change the
4016 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4017 *
4018 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4019 * don't appear to make the mic bias available from the "line" jack, even
4020 * though the NID used for this jack (0x14) can supply it. The theory is
4021 * that perhaps Acer have included blocking capacitors between the ALC260
4022 * and the output jack. If this turns out to be the case for all such
4023 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4024 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004025 *
4026 * The C20x Tablet series have a mono internal speaker which is controlled
4027 * via the chip's Mono sum widget and pin complex, so include the necessary
4028 * controls for such models. On models without a "mono speaker" the control
4029 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004030 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004031static struct snd_kcontrol_new alc260_acer_mixer[] = {
4032 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4033 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004034 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004035 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004036 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004037 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004038 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004039 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4040 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4041 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4042 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4043 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4044 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4045 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4046 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4047 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4048 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4049 { } /* end */
4050};
4051
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004052/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4053 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4054 */
4055static struct snd_kcontrol_new alc260_will_mixer[] = {
4056 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4057 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4058 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4059 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4060 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4061 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4062 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4063 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4064 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4065 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4066 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4067 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4068 { } /* end */
4069};
4070
4071/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4072 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4073 */
4074static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4075 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4076 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4077 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4078 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4079 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4080 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4081 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4082 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4083 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4084 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4085 { } /* end */
4086};
4087
Kailang Yangdf694da2005-12-05 19:42:22 +01004088/* capture mixer elements */
4089static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004090 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4091 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004092 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4093 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004094 {
4095 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004096 /* The multiple "Capture Source" controls confuse alsamixer
4097 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004098 */
4099 /* .name = "Capture Source", */
4100 .name = "Input Source",
4101 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004102 .info = alc_mux_enum_info,
4103 .get = alc_mux_enum_get,
4104 .put = alc_mux_enum_put,
4105 },
4106 { } /* end */
4107};
4108
Kailang Yangdf694da2005-12-05 19:42:22 +01004109static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4110 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4111 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4112 {
4113 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4114 /* The multiple "Capture Source" controls confuse alsamixer
4115 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004116 */
4117 /* .name = "Capture Source", */
4118 .name = "Input Source",
4119 .count = 1,
4120 .info = alc_mux_enum_info,
4121 .get = alc_mux_enum_get,
4122 .put = alc_mux_enum_put,
4123 },
4124 { } /* end */
4125};
4126
4127/*
4128 * initialization verbs
4129 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130static struct hda_verb alc260_init_verbs[] = {
4131 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004132 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004134 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004136 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004138 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004140 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004142 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004144 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004146 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004148 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4149 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004150 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 /* set connection select to line in (default select for this ADC) */
4152 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004153 /* mute capture amp left and right */
4154 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4155 /* set connection select to line in (default select for this ADC) */
4156 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004157 /* set vol=0 Line-Out mixer amp left and right */
4158 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4159 /* unmute pin widget amp left and right (no gain on this amp) */
4160 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4161 /* set vol=0 HP mixer amp left and right */
4162 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4163 /* unmute pin widget amp left and right (no gain on this amp) */
4164 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4165 /* set vol=0 Mono mixer amp left and right */
4166 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4167 /* unmute pin widget amp left and right (no gain on this amp) */
4168 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4169 /* unmute LINE-2 out pin */
4170 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004171 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4172 * Line In 2 = 0x03
4173 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004174 /* mute analog inputs */
4175 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4176 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4177 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4178 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4179 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004181 /* mute Front out path */
4182 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4183 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4184 /* mute Headphone out path */
4185 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4186 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4187 /* mute Mono out path */
4188 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4189 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 { }
4191};
4192
Takashi Iwai474167d2006-05-17 17:17:43 +02004193#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004194static struct hda_verb alc260_hp_init_verbs[] = {
4195 /* Headphone and output */
4196 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4197 /* mono output */
4198 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4199 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4200 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4201 /* Mic2 (front panel) pin widget for input and vref at 80% */
4202 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4203 /* Line In pin widget for input */
4204 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4205 /* Line-2 pin widget for output */
4206 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4207 /* CD pin widget for input */
4208 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4209 /* unmute amp left and right */
4210 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4211 /* set connection select to line in (default select for this ADC) */
4212 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4213 /* unmute Line-Out mixer amp left and right (volume = 0) */
4214 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4215 /* mute pin widget amp left and right (no gain on this amp) */
4216 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4217 /* unmute HP mixer amp left and right (volume = 0) */
4218 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4219 /* mute pin widget amp left and right (no gain on this amp) */
4220 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004221 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4222 * Line In 2 = 0x03
4223 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004224 /* mute analog inputs */
4225 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4226 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4227 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4228 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4229 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004230 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4231 /* Unmute Front out path */
4232 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4233 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4234 /* Unmute Headphone out path */
4235 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4236 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4237 /* Unmute Mono out path */
4238 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4239 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4240 { }
4241};
Takashi Iwai474167d2006-05-17 17:17:43 +02004242#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004243
4244static struct hda_verb alc260_hp_3013_init_verbs[] = {
4245 /* Line out and output */
4246 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4247 /* mono output */
4248 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4249 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4250 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4251 /* Mic2 (front panel) pin widget for input and vref at 80% */
4252 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4253 /* Line In pin widget for input */
4254 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4255 /* Headphone pin widget for output */
4256 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4257 /* CD pin widget for input */
4258 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4259 /* unmute amp left and right */
4260 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4261 /* set connection select to line in (default select for this ADC) */
4262 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4263 /* unmute Line-Out mixer amp left and right (volume = 0) */
4264 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4265 /* mute pin widget amp left and right (no gain on this amp) */
4266 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4267 /* unmute HP mixer amp left and right (volume = 0) */
4268 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4269 /* mute pin widget amp left and right (no gain on this amp) */
4270 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004271 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4272 * Line In 2 = 0x03
4273 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004274 /* mute analog inputs */
4275 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4278 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4279 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004280 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4281 /* Unmute Front out path */
4282 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4283 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4284 /* Unmute Headphone out path */
4285 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4286 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4287 /* Unmute Mono out path */
4288 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4289 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4290 { }
4291};
4292
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004293/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004294 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4295 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004296 */
4297static struct hda_verb alc260_fujitsu_init_verbs[] = {
4298 /* Disable all GPIOs */
4299 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4300 /* Internal speaker is connected to headphone pin */
4301 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4302 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4303 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004304 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4305 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4306 /* Ensure all other unused pins are disabled and muted. */
4307 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4308 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004309 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004310 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004311 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004312 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4313 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4314 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004315
Jonathan Woithef7ace402006-02-28 11:46:14 +01004316 /* Disable digital (SPDIF) pins */
4317 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4318 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004319
Jonathan Woithef7ace402006-02-28 11:46:14 +01004320 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4321 * when acting as an output.
4322 */
4323 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4324
4325 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004326 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4327 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4328 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4329 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4330 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4331 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4332 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4333 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4334 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004335
Jonathan Woithef7ace402006-02-28 11:46:14 +01004336 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4337 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4338 /* Unmute Line1 pin widget output buffer since it starts as an output.
4339 * If the pin mode is changed by the user the pin mode control will
4340 * take care of enabling the pin's input/output buffers as needed.
4341 * Therefore there's no need to enable the input buffer at this
4342 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004343 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004344 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004345 /* Unmute input buffer of pin widget used for Line-in (no equiv
4346 * mixer ctrl)
4347 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004348 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004349
Jonathan Woithef7ace402006-02-28 11:46:14 +01004350 /* Mute capture amp left and right */
4351 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4352 /* Set ADC connection select to match default mixer setting - line
4353 * in (on mic1 pin)
4354 */
4355 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004356
Jonathan Woithef7ace402006-02-28 11:46:14 +01004357 /* Do the same for the second ADC: mute capture input amp and
4358 * set ADC connection to line in (on mic1 pin)
4359 */
4360 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4361 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004362
Jonathan Woithef7ace402006-02-28 11:46:14 +01004363 /* Mute all inputs to mixer widget (even unconnected ones) */
4364 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4365 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4366 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4367 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4368 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4369 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4370 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4371 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004372
4373 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004374};
4375
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004376/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4377 * similar laptops (adapted from Fujitsu init verbs).
4378 */
4379static struct hda_verb alc260_acer_init_verbs[] = {
4380 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4381 * the headphone jack. Turn this on and rely on the standard mute
4382 * methods whenever the user wants to turn these outputs off.
4383 */
4384 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4385 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4386 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4387 /* Internal speaker/Headphone jack is connected to Line-out pin */
4388 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4389 /* Internal microphone/Mic jack is connected to Mic1 pin */
4390 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4391 /* Line In jack is connected to Line1 pin */
4392 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004393 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4394 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004395 /* Ensure all other unused pins are disabled and muted. */
4396 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4397 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004398 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4399 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4400 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4401 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4402 /* Disable digital (SPDIF) pins */
4403 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4404 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4405
4406 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4407 * bus when acting as outputs.
4408 */
4409 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4410 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4411
4412 /* Start with output sum widgets muted and their output gains at min */
4413 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4414 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4415 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4416 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4417 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4418 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4419 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4420 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4421 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4422
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004423 /* Unmute Line-out pin widget amp left and right
4424 * (no equiv mixer ctrl)
4425 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004426 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004427 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4428 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004429 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4430 * inputs. If the pin mode is changed by the user the pin mode control
4431 * will take care of enabling the pin's input/output buffers as needed.
4432 * Therefore there's no need to enable the input buffer at this
4433 * stage.
4434 */
4435 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4436 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4437
4438 /* Mute capture amp left and right */
4439 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4440 /* Set ADC connection select to match default mixer setting - mic
4441 * (on mic1 pin)
4442 */
4443 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4444
4445 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004446 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004447 */
4448 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004449 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004450
4451 /* Mute all inputs to mixer widget (even unconnected ones) */
4452 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4453 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4454 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4455 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4456 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4458 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4459 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4460
4461 { }
4462};
4463
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004464static struct hda_verb alc260_will_verbs[] = {
4465 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4466 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4467 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4468 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4469 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4470 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4471 {}
4472};
4473
4474static struct hda_verb alc260_replacer_672v_verbs[] = {
4475 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4476 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4477 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4478
4479 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4480 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4481 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4482
4483 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4484 {}
4485};
4486
4487/* toggle speaker-output according to the hp-jack state */
4488static void alc260_replacer_672v_automute(struct hda_codec *codec)
4489{
4490 unsigned int present;
4491
4492 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4493 present = snd_hda_codec_read(codec, 0x0f, 0,
4494 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4495 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004496 snd_hda_codec_write_cache(codec, 0x01, 0,
4497 AC_VERB_SET_GPIO_DATA, 1);
4498 snd_hda_codec_write_cache(codec, 0x0f, 0,
4499 AC_VERB_SET_PIN_WIDGET_CONTROL,
4500 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004501 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004502 snd_hda_codec_write_cache(codec, 0x01, 0,
4503 AC_VERB_SET_GPIO_DATA, 0);
4504 snd_hda_codec_write_cache(codec, 0x0f, 0,
4505 AC_VERB_SET_PIN_WIDGET_CONTROL,
4506 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004507 }
4508}
4509
4510static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4511 unsigned int res)
4512{
4513 if ((res >> 26) == ALC880_HP_EVENT)
4514 alc260_replacer_672v_automute(codec);
4515}
4516
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004517/* Test configuration for debugging, modelled after the ALC880 test
4518 * configuration.
4519 */
4520#ifdef CONFIG_SND_DEBUG
4521static hda_nid_t alc260_test_dac_nids[1] = {
4522 0x02,
4523};
4524static hda_nid_t alc260_test_adc_nids[2] = {
4525 0x04, 0x05,
4526};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004527/* For testing the ALC260, each input MUX needs its own definition since
4528 * the signal assignments are different. This assumes that the first ADC
4529 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004530 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004531static struct hda_input_mux alc260_test_capture_sources[2] = {
4532 {
4533 .num_items = 7,
4534 .items = {
4535 { "MIC1 pin", 0x0 },
4536 { "MIC2 pin", 0x1 },
4537 { "LINE1 pin", 0x2 },
4538 { "LINE2 pin", 0x3 },
4539 { "CD pin", 0x4 },
4540 { "LINE-OUT pin", 0x5 },
4541 { "HP-OUT pin", 0x6 },
4542 },
4543 },
4544 {
4545 .num_items = 8,
4546 .items = {
4547 { "MIC1 pin", 0x0 },
4548 { "MIC2 pin", 0x1 },
4549 { "LINE1 pin", 0x2 },
4550 { "LINE2 pin", 0x3 },
4551 { "CD pin", 0x4 },
4552 { "Mixer", 0x5 },
4553 { "LINE-OUT pin", 0x6 },
4554 { "HP-OUT pin", 0x7 },
4555 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004556 },
4557};
4558static struct snd_kcontrol_new alc260_test_mixer[] = {
4559 /* Output driver widgets */
4560 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4561 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4562 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4563 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4564 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4565 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4566
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004567 /* Modes for retasking pin widgets
4568 * Note: the ALC260 doesn't seem to act on requests to enable mic
4569 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4570 * mention this restriction. At this stage it's not clear whether
4571 * this behaviour is intentional or is a hardware bug in chip
4572 * revisions available at least up until early 2006. Therefore for
4573 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4574 * choices, but if it turns out that the lack of mic bias for these
4575 * NIDs is intentional we could change their modes from
4576 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4577 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004578 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4579 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4580 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4581 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4582 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4583 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4584
4585 /* Loopback mixer controls */
4586 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4587 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4588 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4589 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4590 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4591 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4592 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4593 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4594 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4595 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4596 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4597 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4598 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4599 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4600 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4601 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004602
4603 /* Controls for GPIO pins, assuming they are configured as outputs */
4604 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4605 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4606 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4607 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4608
Jonathan Woithe92621f12006-02-28 11:47:47 +01004609 /* Switches to allow the digital IO pins to be enabled. The datasheet
4610 * is ambigious as to which NID is which; testing on laptops which
4611 * make this output available should provide clarification.
4612 */
4613 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4614 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4615
Jonathan Woithef8225f62008-01-08 12:16:54 +01004616 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4617 * this output to turn on an external amplifier.
4618 */
4619 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4620 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4621
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004622 { } /* end */
4623};
4624static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004625 /* Enable all GPIOs as outputs with an initial value of 0 */
4626 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4627 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4628 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4629
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004630 /* Enable retasking pins as output, initially without power amp */
4631 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4632 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4633 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4634 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4635 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4636 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4637
Jonathan Woithe92621f12006-02-28 11:47:47 +01004638 /* Disable digital (SPDIF) pins initially, but users can enable
4639 * them via a mixer switch. In the case of SPDIF-out, this initverb
4640 * payload also sets the generation to 0, output to be in "consumer"
4641 * PCM format, copyright asserted, no pre-emphasis and no validity
4642 * control.
4643 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004644 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4645 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4646
Jonathan Woithef7ace402006-02-28 11:46:14 +01004647 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004648 * OUT1 sum bus when acting as an output.
4649 */
4650 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4651 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4652 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4653 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4654
4655 /* Start with output sum widgets muted and their output gains at min */
4656 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4657 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4658 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4659 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4660 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4661 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4662 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4663 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4664 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4665
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004666 /* Unmute retasking pin widget output buffers since the default
4667 * state appears to be output. As the pin mode is changed by the
4668 * user the pin mode control will take care of enabling the pin's
4669 * input/output buffers as needed.
4670 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004671 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4672 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4673 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4674 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4675 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4676 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4677 /* Also unmute the mono-out pin widget */
4678 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4679
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004680 /* Mute capture amp left and right */
4681 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004682 /* Set ADC connection select to match default mixer setting (mic1
4683 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004684 */
4685 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4686
4687 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004688 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004689 */
4690 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4691 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4692
4693 /* Mute all inputs to mixer widget (even unconnected ones) */
4694 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4695 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4696 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4697 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4698 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4699 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4700 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4701 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4702
4703 { }
4704};
4705#endif
4706
Takashi Iwai63300792008-01-24 15:31:36 +01004707#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4708#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004710#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4711#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4712
Kailang Yangdf694da2005-12-05 19:42:22 +01004713/*
4714 * for BIOS auto-configuration
4715 */
4716
4717static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4718 const char *pfx)
4719{
4720 hda_nid_t nid_vol;
4721 unsigned long vol_val, sw_val;
4722 char name[32];
4723 int err;
4724
4725 if (nid >= 0x0f && nid < 0x11) {
4726 nid_vol = nid - 0x7;
4727 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4728 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4729 } else if (nid == 0x11) {
4730 nid_vol = nid - 0x7;
4731 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4732 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4733 } else if (nid >= 0x12 && nid <= 0x15) {
4734 nid_vol = 0x08;
4735 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4736 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4737 } else
4738 return 0; /* N/A */
4739
4740 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004741 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4742 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004743 return err;
4744 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004745 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4746 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004747 return err;
4748 return 1;
4749}
4750
4751/* add playback controls from the parsed DAC table */
4752static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4753 const struct auto_pin_cfg *cfg)
4754{
4755 hda_nid_t nid;
4756 int err;
4757
4758 spec->multiout.num_dacs = 1;
4759 spec->multiout.dac_nids = spec->private_dac_nids;
4760 spec->multiout.dac_nids[0] = 0x02;
4761
4762 nid = cfg->line_out_pins[0];
4763 if (nid) {
4764 err = alc260_add_playback_controls(spec, nid, "Front");
4765 if (err < 0)
4766 return err;
4767 }
4768
Takashi Iwai82bc9552006-03-21 11:24:42 +01004769 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004770 if (nid) {
4771 err = alc260_add_playback_controls(spec, nid, "Speaker");
4772 if (err < 0)
4773 return err;
4774 }
4775
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004776 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004777 if (nid) {
4778 err = alc260_add_playback_controls(spec, nid, "Headphone");
4779 if (err < 0)
4780 return err;
4781 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004782 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004783}
4784
4785/* create playback/capture controls for input pins */
4786static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4787 const struct auto_pin_cfg *cfg)
4788{
Kailang Yangdf694da2005-12-05 19:42:22 +01004789 struct hda_input_mux *imux = &spec->private_imux;
4790 int i, err, idx;
4791
4792 for (i = 0; i < AUTO_PIN_LAST; i++) {
4793 if (cfg->input_pins[i] >= 0x12) {
4794 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004795 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004796 auto_pin_cfg_labels[i], idx,
4797 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004798 if (err < 0)
4799 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004800 imux->items[imux->num_items].label =
4801 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004802 imux->items[imux->num_items].index = idx;
4803 imux->num_items++;
4804 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004805 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004806 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004807 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004808 auto_pin_cfg_labels[i], idx,
4809 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004810 if (err < 0)
4811 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004812 imux->items[imux->num_items].label =
4813 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004814 imux->items[imux->num_items].index = idx;
4815 imux->num_items++;
4816 }
4817 }
4818 return 0;
4819}
4820
4821static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4822 hda_nid_t nid, int pin_type,
4823 int sel_idx)
4824{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004825 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01004826 /* need the manual connection? */
4827 if (nid >= 0x12) {
4828 int idx = nid - 0x12;
4829 snd_hda_codec_write(codec, idx + 0x0b, 0,
4830 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004831 }
4832}
4833
4834static void alc260_auto_init_multi_out(struct hda_codec *codec)
4835{
4836 struct alc_spec *spec = codec->spec;
4837 hda_nid_t nid;
4838
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004839 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004840 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004841 if (nid) {
4842 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4843 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4844 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004845
Takashi Iwai82bc9552006-03-21 11:24:42 +01004846 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004847 if (nid)
4848 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4849
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004850 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004851 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004852 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004853}
Kailang Yangdf694da2005-12-05 19:42:22 +01004854
4855#define ALC260_PIN_CD_NID 0x16
4856static void alc260_auto_init_analog_input(struct hda_codec *codec)
4857{
4858 struct alc_spec *spec = codec->spec;
4859 int i;
4860
4861 for (i = 0; i < AUTO_PIN_LAST; i++) {
4862 hda_nid_t nid = spec->autocfg.input_pins[i];
4863 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004864 snd_hda_codec_write(codec, nid, 0,
4865 AC_VERB_SET_PIN_WIDGET_CONTROL,
4866 i <= AUTO_PIN_FRONT_MIC ?
4867 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004868 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004869 snd_hda_codec_write(codec, nid, 0,
4870 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004871 AMP_OUT_MUTE);
4872 }
4873 }
4874}
4875
4876/*
4877 * generic initialization of ADC, input mixers and output mixers
4878 */
4879static struct hda_verb alc260_volume_init_verbs[] = {
4880 /*
4881 * Unmute ADC0-1 and set the default input to mic-in
4882 */
4883 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4884 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4885 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4886 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4887
4888 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4889 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004890 * Note: PASD motherboards uses the Line In 2 as the input for
4891 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004892 */
4893 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004894 /* mute analog inputs */
4895 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4896 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4897 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4898 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4899 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004900
4901 /*
4902 * Set up output mixers (0x08 - 0x0a)
4903 */
4904 /* set vol=0 to output mixers */
4905 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4906 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4907 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4908 /* set up input amps for analog loopback */
4909 /* Amp Indices: DAC = 0, mixer = 1 */
4910 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4911 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4912 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4913 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4914 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4915 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4916
4917 { }
4918};
4919
4920static int alc260_parse_auto_config(struct hda_codec *codec)
4921{
4922 struct alc_spec *spec = codec->spec;
4923 unsigned int wcap;
4924 int err;
4925 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
4926
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004927 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4928 alc260_ignore);
4929 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004930 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004931 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
4932 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01004933 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004934 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01004935 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004936 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
4937 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004938 return err;
4939
4940 spec->multiout.max_channels = 2;
4941
4942 if (spec->autocfg.dig_out_pin)
4943 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
4944 if (spec->kctl_alloc)
4945 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4946
4947 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
4948
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004949 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01004950 spec->input_mux = &spec->private_imux;
4951
4952 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004953 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01004954 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
Takashi Iwai67ebcb02008-02-19 15:03:57 +01004955 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004956 spec->adc_nids = alc260_adc_nids_alt;
4957 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
4958 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004959 } else {
4960 spec->adc_nids = alc260_adc_nids;
4961 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
4962 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004963 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004964 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01004965
4966 return 1;
4967}
4968
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004969/* additional initialization for auto-configuration model */
4970static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01004971{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004972 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004973 alc260_auto_init_multi_out(codec);
4974 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004975 if (spec->unsol_event)
4976 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01004977}
4978
Takashi Iwaicb53c622007-08-10 17:21:45 +02004979#ifdef CONFIG_SND_HDA_POWER_SAVE
4980static struct hda_amp_list alc260_loopbacks[] = {
4981 { 0x07, HDA_INPUT, 0 },
4982 { 0x07, HDA_INPUT, 1 },
4983 { 0x07, HDA_INPUT, 2 },
4984 { 0x07, HDA_INPUT, 3 },
4985 { 0x07, HDA_INPUT, 4 },
4986 { } /* end */
4987};
4988#endif
4989
Kailang Yangdf694da2005-12-05 19:42:22 +01004990/*
4991 * ALC260 configurations
4992 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004993static const char *alc260_models[ALC260_MODEL_LAST] = {
4994 [ALC260_BASIC] = "basic",
4995 [ALC260_HP] = "hp",
4996 [ALC260_HP_3013] = "hp-3013",
4997 [ALC260_FUJITSU_S702X] = "fujitsu",
4998 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004999 [ALC260_WILL] = "will",
5000 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005001#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005002 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005003#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005004 [ALC260_AUTO] = "auto",
5005};
5006
5007static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005008 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005009 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005010 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005011 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005012 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
5013 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
5014 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
5015 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5016 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5017 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5018 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5019 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5020 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5021 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5022 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5023 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005024 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005025 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005026 {}
5027};
5028
Kailang Yangdf694da2005-12-05 19:42:22 +01005029static struct alc_config_preset alc260_presets[] = {
5030 [ALC260_BASIC] = {
5031 .mixers = { alc260_base_output_mixer,
5032 alc260_input_mixer,
5033 alc260_pc_beep_mixer,
5034 alc260_capture_mixer },
5035 .init_verbs = { alc260_init_verbs },
5036 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5037 .dac_nids = alc260_dac_nids,
5038 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5039 .adc_nids = alc260_adc_nids,
5040 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5041 .channel_mode = alc260_modes,
5042 .input_mux = &alc260_capture_source,
5043 },
5044 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005045 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005046 alc260_input_mixer,
5047 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005048 .init_verbs = { alc260_init_verbs,
5049 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005050 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5051 .dac_nids = alc260_dac_nids,
5052 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5053 .adc_nids = alc260_hp_adc_nids,
5054 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5055 .channel_mode = alc260_modes,
5056 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005057 .unsol_event = alc260_hp_unsol_event,
5058 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005059 },
5060 [ALC260_HP_3013] = {
5061 .mixers = { alc260_hp_3013_mixer,
5062 alc260_input_mixer,
5063 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005064 .init_verbs = { alc260_hp_3013_init_verbs,
5065 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005066 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5067 .dac_nids = alc260_dac_nids,
5068 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5069 .adc_nids = alc260_hp_adc_nids,
5070 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5071 .channel_mode = alc260_modes,
5072 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005073 .unsol_event = alc260_hp_3013_unsol_event,
5074 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005075 },
5076 [ALC260_FUJITSU_S702X] = {
5077 .mixers = { alc260_fujitsu_mixer,
5078 alc260_capture_mixer },
5079 .init_verbs = { alc260_fujitsu_init_verbs },
5080 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5081 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005082 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5083 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005084 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5085 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005086 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5087 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005088 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005089 [ALC260_ACER] = {
5090 .mixers = { alc260_acer_mixer,
5091 alc260_capture_mixer },
5092 .init_verbs = { alc260_acer_init_verbs },
5093 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5094 .dac_nids = alc260_dac_nids,
5095 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5096 .adc_nids = alc260_dual_adc_nids,
5097 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5098 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005099 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5100 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005101 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005102 [ALC260_WILL] = {
5103 .mixers = { alc260_will_mixer,
5104 alc260_capture_mixer },
5105 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5106 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5107 .dac_nids = alc260_dac_nids,
5108 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5109 .adc_nids = alc260_adc_nids,
5110 .dig_out_nid = ALC260_DIGOUT_NID,
5111 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5112 .channel_mode = alc260_modes,
5113 .input_mux = &alc260_capture_source,
5114 },
5115 [ALC260_REPLACER_672V] = {
5116 .mixers = { alc260_replacer_672v_mixer,
5117 alc260_capture_mixer },
5118 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5119 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5120 .dac_nids = alc260_dac_nids,
5121 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5122 .adc_nids = alc260_adc_nids,
5123 .dig_out_nid = ALC260_DIGOUT_NID,
5124 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5125 .channel_mode = alc260_modes,
5126 .input_mux = &alc260_capture_source,
5127 .unsol_event = alc260_replacer_672v_unsol_event,
5128 .init_hook = alc260_replacer_672v_automute,
5129 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005130#ifdef CONFIG_SND_DEBUG
5131 [ALC260_TEST] = {
5132 .mixers = { alc260_test_mixer,
5133 alc260_capture_mixer },
5134 .init_verbs = { alc260_test_init_verbs },
5135 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5136 .dac_nids = alc260_test_dac_nids,
5137 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5138 .adc_nids = alc260_test_adc_nids,
5139 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5140 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005141 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5142 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005143 },
5144#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005145};
5146
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147static int patch_alc260(struct hda_codec *codec)
5148{
5149 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005150 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005152 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 if (spec == NULL)
5154 return -ENOMEM;
5155
5156 codec->spec = spec;
5157
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005158 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5159 alc260_models,
5160 alc260_cfg_tbl);
5161 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005162 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5163 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005164 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005165 }
5166
Kailang Yangdf694da2005-12-05 19:42:22 +01005167 if (board_config == ALC260_AUTO) {
5168 /* automatic parse from the BIOS config */
5169 err = alc260_parse_auto_config(codec);
5170 if (err < 0) {
5171 alc_free(codec);
5172 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005173 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005174 printk(KERN_INFO
5175 "hda_codec: Cannot set up configuration "
5176 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005177 board_config = ALC260_BASIC;
5178 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180
Kailang Yangdf694da2005-12-05 19:42:22 +01005181 if (board_config != ALC260_AUTO)
5182 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183
5184 spec->stream_name_analog = "ALC260 Analog";
5185 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5186 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5187
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005188 spec->stream_name_digital = "ALC260 Digital";
5189 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5190 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5191
Takashi Iwai2134ea42008-01-10 16:53:55 +01005192 spec->vmaster_nid = 0x08;
5193
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005195 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005196 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005197#ifdef CONFIG_SND_HDA_POWER_SAVE
5198 if (!spec->loopback.amplist)
5199 spec->loopback.amplist = alc260_loopbacks;
5200#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201
5202 return 0;
5203}
5204
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005205
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206/*
5207 * ALC882 support
5208 *
5209 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5210 * configuration. Each pin widget can choose any input DACs and a mixer.
5211 * Each ADC is connected from a mixer of all inputs. This makes possible
5212 * 6-channel independent captures.
5213 *
5214 * In addition, an independent DAC for the multi-playback (not used in this
5215 * driver yet).
5216 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005217#define ALC882_DIGOUT_NID 0x06
5218#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005220static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 { 8, NULL }
5222};
5223
5224static hda_nid_t alc882_dac_nids[4] = {
5225 /* front, rear, clfe, rear_surr */
5226 0x02, 0x03, 0x04, 0x05
5227};
5228
Kailang Yangdf694da2005-12-05 19:42:22 +01005229/* identical with ALC880 */
5230#define alc882_adc_nids alc880_adc_nids
5231#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232
Takashi Iwaie1406342008-02-11 18:32:32 +01005233static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5234static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5235
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236/* input MUX */
5237/* FIXME: should be a matrix-type input source selection */
5238
5239static struct hda_input_mux alc882_capture_source = {
5240 .num_items = 4,
5241 .items = {
5242 { "Mic", 0x0 },
5243 { "Front Mic", 0x1 },
5244 { "Line", 0x2 },
5245 { "CD", 0x4 },
5246 },
5247};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248#define alc882_mux_enum_info alc_mux_enum_info
5249#define alc882_mux_enum_get alc_mux_enum_get
5250
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005251static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5252 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253{
5254 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5255 struct alc_spec *spec = codec->spec;
5256 const struct hda_input_mux *imux = spec->input_mux;
5257 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai88c71a92008-02-14 17:27:17 +01005258 hda_nid_t nid = spec->capsrc_nids ?
5259 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5261 unsigned int i, idx;
5262
5263 idx = ucontrol->value.enumerated.item[0];
5264 if (idx >= imux->num_items)
5265 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005266 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 return 0;
5268 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005269 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5270 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005271 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005272 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 }
5274 *cur_val = idx;
5275 return 1;
5276}
5277
Kailang Yangdf694da2005-12-05 19:42:22 +01005278/*
Kailang Yang272a5272007-05-14 11:00:38 +02005279 * 2ch mode
5280 */
5281static struct hda_verb alc882_3ST_ch2_init[] = {
5282 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5283 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5284 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5285 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5286 { } /* end */
5287};
5288
5289/*
5290 * 6ch mode
5291 */
5292static struct hda_verb alc882_3ST_ch6_init[] = {
5293 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5294 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5295 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5296 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5297 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5298 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5299 { } /* end */
5300};
5301
5302static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5303 { 2, alc882_3ST_ch2_init },
5304 { 6, alc882_3ST_ch6_init },
5305};
5306
5307/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005308 * 6ch mode
5309 */
5310static struct hda_verb alc882_sixstack_ch6_init[] = {
5311 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5312 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5313 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5314 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5315 { } /* end */
5316};
5317
5318/*
5319 * 8ch mode
5320 */
5321static struct hda_verb alc882_sixstack_ch8_init[] = {
5322 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5323 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5324 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5325 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5326 { } /* end */
5327};
5328
5329static struct hda_channel_mode alc882_sixstack_modes[2] = {
5330 { 6, alc882_sixstack_ch6_init },
5331 { 8, alc882_sixstack_ch8_init },
5332};
5333
Takashi Iwai87350ad2007-08-16 18:19:38 +02005334/*
5335 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5336 */
5337
5338/*
5339 * 2ch mode
5340 */
5341static struct hda_verb alc885_mbp_ch2_init[] = {
5342 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5343 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5344 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5345 { } /* end */
5346};
5347
5348/*
5349 * 6ch mode
5350 */
5351static struct hda_verb alc885_mbp_ch6_init[] = {
5352 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5353 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5354 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5355 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5356 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5357 { } /* end */
5358};
5359
5360static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5361 { 2, alc885_mbp_ch2_init },
5362 { 6, alc885_mbp_ch6_init },
5363};
5364
5365
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5367 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5368 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005369static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005370 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005371 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005372 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005373 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005374 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5375 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005376 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5377 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005378 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005379 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5381 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5382 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5383 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5384 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5385 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005386 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5388 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005389 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5391 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5392 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 { } /* end */
5394};
5395
Takashi Iwai87350ad2007-08-16 18:19:38 +02005396static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005397 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5398 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5399 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5400 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5401 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5402 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005403 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5404 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005405 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005406 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5407 { } /* end */
5408};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005409static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5410 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5411 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5412 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5413 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5414 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5415 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5416 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5417 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5418 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5419 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5420 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5421 { } /* end */
5422};
5423
Kailang Yang272a5272007-05-14 11:00:38 +02005424static struct snd_kcontrol_new alc882_targa_mixer[] = {
5425 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5426 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5427 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5428 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5429 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5430 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5431 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5432 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5433 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005434 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005435 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5436 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005437 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005438 { } /* end */
5439};
5440
5441/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5442 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5443 */
5444static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5445 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5446 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5447 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5448 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5449 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5450 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5451 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5452 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5453 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5454 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5455 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5456 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005457 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005458 { } /* end */
5459};
5460
Takashi Iwai914759b2007-09-06 14:52:04 +02005461static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5462 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5463 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5464 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5465 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5466 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5467 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5468 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5469 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5470 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5471 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5472 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5473 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5474 { } /* end */
5475};
5476
Kailang Yangdf694da2005-12-05 19:42:22 +01005477static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5478 {
5479 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5480 .name = "Channel Mode",
5481 .info = alc_ch_mode_info,
5482 .get = alc_ch_mode_get,
5483 .put = alc_ch_mode_put,
5484 },
5485 { } /* end */
5486};
5487
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488static struct hda_verb alc882_init_verbs[] = {
5489 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005490 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5491 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5492 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005494 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5495 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5496 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005498 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5499 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5500 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005502 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5503 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5504 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005506 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005507 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005508 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005510 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005511 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005512 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005514 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005515 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005516 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005518 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005519 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005520 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005522 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005523 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005524 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5525 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005526 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005527 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5528 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005529 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005530 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5531 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5532 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5533 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5534 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005536 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
5538 /* FIXME: use matrix-type input source selection */
5539 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5540 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005541 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5542 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5543 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5544 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005546 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5547 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5548 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5549 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005551 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5552 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5553 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5554 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5555 /* ADC1: mute amp left and right */
5556 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005557 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005558 /* ADC2: mute amp left and right */
5559 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005560 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005561 /* ADC3: mute amp left and right */
5562 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005563 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564
5565 { }
5566};
5567
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005568static struct hda_verb alc882_eapd_verbs[] = {
5569 /* change to EAPD mode */
5570 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005571 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005572 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005573};
5574
Tobin Davis9102cd12006-12-15 10:02:12 +01005575/* Mac Pro test */
5576static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5577 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5578 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5579 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5580 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5581 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5582 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5583 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5584 { } /* end */
5585};
5586
5587static struct hda_verb alc882_macpro_init_verbs[] = {
5588 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5589 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5590 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5592 /* Front Pin: output 0 (0x0c) */
5593 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5594 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5595 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5596 /* Front Mic pin: input vref at 80% */
5597 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5598 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5599 /* Speaker: output */
5600 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5601 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5602 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5603 /* Headphone output (output 0 - 0x0c) */
5604 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5605 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5606 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5607
5608 /* FIXME: use matrix-type input source selection */
5609 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5610 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5611 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5612 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5613 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5614 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5615 /* Input mixer2 */
5616 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5617 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5618 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5619 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5620 /* Input mixer3 */
5621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5622 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5623 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5624 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5625 /* ADC1: mute amp left and right */
5626 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5627 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5628 /* ADC2: mute amp left and right */
5629 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5630 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5631 /* ADC3: mute amp left and right */
5632 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5633 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5634
5635 { }
5636};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005637
Takashi Iwai87350ad2007-08-16 18:19:38 +02005638/* Macbook Pro rev3 */
5639static struct hda_verb alc885_mbp3_init_verbs[] = {
5640 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5641 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5642 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5643 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5644 /* Rear mixer */
5645 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5646 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5647 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5648 /* Front Pin: output 0 (0x0c) */
5649 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5650 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5651 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5652 /* HP Pin: output 0 (0x0d) */
5653 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5654 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5655 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5656 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5657 /* Mic (rear) pin: input vref at 80% */
5658 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5659 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5660 /* Front Mic pin: input vref at 80% */
5661 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5662 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5663 /* Line In pin: use output 1 when in LineOut mode */
5664 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5665 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5666 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5667
5668 /* FIXME: use matrix-type input source selection */
5669 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5670 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5671 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5672 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5673 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5674 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5675 /* Input mixer2 */
5676 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5677 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5678 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5679 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5680 /* Input mixer3 */
5681 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5682 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5683 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5684 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5685 /* ADC1: mute amp left and right */
5686 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5687 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5688 /* ADC2: mute amp left and right */
5689 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5690 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5691 /* ADC3: mute amp left and right */
5692 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5693 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5694
5695 { }
5696};
5697
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005698/* iMac 24 mixer. */
5699static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5700 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5701 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5702 { } /* end */
5703};
5704
5705/* iMac 24 init verbs. */
5706static struct hda_verb alc885_imac24_init_verbs[] = {
5707 /* Internal speakers: output 0 (0x0c) */
5708 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5709 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5710 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5711 /* Internal speakers: output 0 (0x0c) */
5712 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5713 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5714 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5715 /* Headphone: output 0 (0x0c) */
5716 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5717 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5718 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5719 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5720 /* Front Mic: input vref at 80% */
5721 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5722 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5723 { }
5724};
5725
5726/* Toggle speaker-output according to the hp-jack state */
5727static void alc885_imac24_automute(struct hda_codec *codec)
5728{
5729 unsigned int present;
5730
5731 present = snd_hda_codec_read(codec, 0x14, 0,
5732 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005733 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5734 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5735 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5736 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005737}
5738
5739/* Processes unsolicited events. */
5740static void alc885_imac24_unsol_event(struct hda_codec *codec,
5741 unsigned int res)
5742{
5743 /* Headphone insertion or removal. */
5744 if ((res >> 26) == ALC880_HP_EVENT)
5745 alc885_imac24_automute(codec);
5746}
5747
Takashi Iwai87350ad2007-08-16 18:19:38 +02005748static void alc885_mbp3_automute(struct hda_codec *codec)
5749{
5750 unsigned int present;
5751
5752 present = snd_hda_codec_read(codec, 0x15, 0,
5753 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5754 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5755 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5756 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5757 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5758
5759}
5760static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5761 unsigned int res)
5762{
5763 /* Headphone insertion or removal. */
5764 if ((res >> 26) == ALC880_HP_EVENT)
5765 alc885_mbp3_automute(codec);
5766}
5767
5768
Kailang Yang272a5272007-05-14 11:00:38 +02005769static struct hda_verb alc882_targa_verbs[] = {
5770 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5771 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5772
5773 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5774 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5775
5776 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5777 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5778 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5779
5780 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5781 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5782 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5783 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5784 { } /* end */
5785};
5786
5787/* toggle speaker-output according to the hp-jack state */
5788static void alc882_targa_automute(struct hda_codec *codec)
5789{
5790 unsigned int present;
5791
5792 present = snd_hda_codec_read(codec, 0x14, 0,
5793 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005794 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5795 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005796 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5797 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005798}
5799
5800static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5801{
5802 /* Looks like the unsol event is incompatible with the standard
5803 * definition. 4bit tag is placed at 26 bit!
5804 */
5805 if (((res >> 26) == ALC880_HP_EVENT)) {
5806 alc882_targa_automute(codec);
5807 }
5808}
5809
5810static struct hda_verb alc882_asus_a7j_verbs[] = {
5811 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5812 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5813
5814 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5815 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5816 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5817
5818 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5819 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5820 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5821
5822 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5823 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5824 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5825 { } /* end */
5826};
5827
Takashi Iwai914759b2007-09-06 14:52:04 +02005828static struct hda_verb alc882_asus_a7m_verbs[] = {
5829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5830 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5831
5832 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5833 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5834 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5835
5836 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5837 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5838 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5839
5840 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5841 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5842 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5843 { } /* end */
5844};
5845
Tobin Davis9102cd12006-12-15 10:02:12 +01005846static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5847{
5848 unsigned int gpiostate, gpiomask, gpiodir;
5849
5850 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5851 AC_VERB_GET_GPIO_DATA, 0);
5852
5853 if (!muted)
5854 gpiostate |= (1 << pin);
5855 else
5856 gpiostate &= ~(1 << pin);
5857
5858 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5859 AC_VERB_GET_GPIO_MASK, 0);
5860 gpiomask |= (1 << pin);
5861
5862 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5863 AC_VERB_GET_GPIO_DIRECTION, 0);
5864 gpiodir |= (1 << pin);
5865
5866
5867 snd_hda_codec_write(codec, codec->afg, 0,
5868 AC_VERB_SET_GPIO_MASK, gpiomask);
5869 snd_hda_codec_write(codec, codec->afg, 0,
5870 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5871
5872 msleep(1);
5873
5874 snd_hda_codec_write(codec, codec->afg, 0,
5875 AC_VERB_SET_GPIO_DATA, gpiostate);
5876}
5877
Takashi Iwai7debbe52007-08-16 15:01:03 +02005878/* set up GPIO at initialization */
5879static void alc885_macpro_init_hook(struct hda_codec *codec)
5880{
5881 alc882_gpio_mute(codec, 0, 0);
5882 alc882_gpio_mute(codec, 1, 0);
5883}
5884
5885/* set up GPIO and update auto-muting at initialization */
5886static void alc885_imac24_init_hook(struct hda_codec *codec)
5887{
5888 alc885_macpro_init_hook(codec);
5889 alc885_imac24_automute(codec);
5890}
5891
Kailang Yangdf694da2005-12-05 19:42:22 +01005892/*
5893 * generic initialization of ADC, input mixers and output mixers
5894 */
5895static struct hda_verb alc882_auto_init_verbs[] = {
5896 /*
5897 * Unmute ADC0-2 and set the default input to mic-in
5898 */
5899 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5900 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5901 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5902 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5903 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5904 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5905
Takashi Iwaicb53c622007-08-10 17:21:45 +02005906 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01005907 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005908 * Note: PASD motherboards uses the Line In 2 as the input for
5909 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005910 */
5911 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005912 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5913 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5914 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5915 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5916 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005917
5918 /*
5919 * Set up output mixers (0x0c - 0x0f)
5920 */
5921 /* set vol=0 to output mixers */
5922 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5923 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5924 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5925 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5926 /* set up input amps for analog loopback */
5927 /* Amp Indices: DAC = 0, mixer = 1 */
5928 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5929 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5930 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5931 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5932 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5933 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5934 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5935 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5936 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5937 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5938
5939 /* FIXME: use matrix-type input source selection */
5940 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5941 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5942 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5943 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5944 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5945 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5946 /* Input mixer2 */
5947 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5948 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5949 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5950 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5951 /* Input mixer3 */
5952 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5953 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5954 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5955 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5956
5957 { }
5958};
5959
5960/* capture mixer elements */
5961static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
5962 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5963 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5964 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5965 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5966 {
5967 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5968 /* The multiple "Capture Source" controls confuse alsamixer
5969 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005970 */
5971 /* .name = "Capture Source", */
5972 .name = "Input Source",
5973 .count = 2,
5974 .info = alc882_mux_enum_info,
5975 .get = alc882_mux_enum_get,
5976 .put = alc882_mux_enum_put,
5977 },
5978 { } /* end */
5979};
5980
5981static struct snd_kcontrol_new alc882_capture_mixer[] = {
5982 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
5983 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
5984 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
5985 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
5986 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
5987 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
5988 {
5989 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5990 /* The multiple "Capture Source" controls confuse alsamixer
5991 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005992 */
5993 /* .name = "Capture Source", */
5994 .name = "Input Source",
5995 .count = 3,
5996 .info = alc882_mux_enum_info,
5997 .get = alc882_mux_enum_get,
5998 .put = alc882_mux_enum_put,
5999 },
6000 { } /* end */
6001};
6002
Takashi Iwaicb53c622007-08-10 17:21:45 +02006003#ifdef CONFIG_SND_HDA_POWER_SAVE
6004#define alc882_loopbacks alc880_loopbacks
6005#endif
6006
Kailang Yangdf694da2005-12-05 19:42:22 +01006007/* pcm configuration: identiacal with ALC880 */
6008#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6009#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6010#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6011#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6012
6013/*
6014 * configuration and preset
6015 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006016static const char *alc882_models[ALC882_MODEL_LAST] = {
6017 [ALC882_3ST_DIG] = "3stack-dig",
6018 [ALC882_6ST_DIG] = "6stack-dig",
6019 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006020 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006021 [ALC882_TARGA] = "targa",
6022 [ALC882_ASUS_A7J] = "asus-a7j",
6023 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006024 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006025 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006026 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006027 [ALC882_AUTO] = "auto",
6028};
6029
6030static struct snd_pci_quirk alc882_cfg_tbl[] = {
6031 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006032 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006033 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006034 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006035 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006036 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006037 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006038 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006039 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006040 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6041 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6042 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006043 {}
6044};
6045
6046static struct alc_config_preset alc882_presets[] = {
6047 [ALC882_3ST_DIG] = {
6048 .mixers = { alc882_base_mixer },
6049 .init_verbs = { alc882_init_verbs },
6050 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6051 .dac_nids = alc882_dac_nids,
6052 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006053 .dig_in_nid = ALC882_DIGIN_NID,
6054 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6055 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006056 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006057 .input_mux = &alc882_capture_source,
6058 },
6059 [ALC882_6ST_DIG] = {
6060 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6061 .init_verbs = { alc882_init_verbs },
6062 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6063 .dac_nids = alc882_dac_nids,
6064 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006065 .dig_in_nid = ALC882_DIGIN_NID,
6066 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6067 .channel_mode = alc882_sixstack_modes,
6068 .input_mux = &alc882_capture_source,
6069 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006070 [ALC882_ARIMA] = {
6071 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6072 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6073 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6074 .dac_nids = alc882_dac_nids,
6075 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6076 .channel_mode = alc882_sixstack_modes,
6077 .input_mux = &alc882_capture_source,
6078 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006079 [ALC882_W2JC] = {
6080 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6081 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6082 alc880_gpio1_init_verbs },
6083 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6084 .dac_nids = alc882_dac_nids,
6085 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6086 .channel_mode = alc880_threestack_modes,
6087 .need_dac_fix = 1,
6088 .input_mux = &alc882_capture_source,
6089 .dig_out_nid = ALC882_DIGOUT_NID,
6090 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006091 [ALC885_MBP3] = {
6092 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6093 .init_verbs = { alc885_mbp3_init_verbs,
6094 alc880_gpio1_init_verbs },
6095 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6096 .dac_nids = alc882_dac_nids,
6097 .channel_mode = alc885_mbp_6ch_modes,
6098 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6099 .input_mux = &alc882_capture_source,
6100 .dig_out_nid = ALC882_DIGOUT_NID,
6101 .dig_in_nid = ALC882_DIGIN_NID,
6102 .unsol_event = alc885_mbp3_unsol_event,
6103 .init_hook = alc885_mbp3_automute,
6104 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006105 [ALC885_MACPRO] = {
6106 .mixers = { alc882_macpro_mixer },
6107 .init_verbs = { alc882_macpro_init_verbs },
6108 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6109 .dac_nids = alc882_dac_nids,
6110 .dig_out_nid = ALC882_DIGOUT_NID,
6111 .dig_in_nid = ALC882_DIGIN_NID,
6112 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6113 .channel_mode = alc882_ch_modes,
6114 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006115 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006116 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006117 [ALC885_IMAC24] = {
6118 .mixers = { alc885_imac24_mixer },
6119 .init_verbs = { alc885_imac24_init_verbs },
6120 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6121 .dac_nids = alc882_dac_nids,
6122 .dig_out_nid = ALC882_DIGOUT_NID,
6123 .dig_in_nid = ALC882_DIGIN_NID,
6124 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6125 .channel_mode = alc882_ch_modes,
6126 .input_mux = &alc882_capture_source,
6127 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006128 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006129 },
Kailang Yang272a5272007-05-14 11:00:38 +02006130 [ALC882_TARGA] = {
6131 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6132 alc882_capture_mixer },
6133 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6134 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6135 .dac_nids = alc882_dac_nids,
6136 .dig_out_nid = ALC882_DIGOUT_NID,
6137 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6138 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006139 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006140 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6141 .channel_mode = alc882_3ST_6ch_modes,
6142 .need_dac_fix = 1,
6143 .input_mux = &alc882_capture_source,
6144 .unsol_event = alc882_targa_unsol_event,
6145 .init_hook = alc882_targa_automute,
6146 },
6147 [ALC882_ASUS_A7J] = {
6148 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6149 alc882_capture_mixer },
6150 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6151 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6152 .dac_nids = alc882_dac_nids,
6153 .dig_out_nid = ALC882_DIGOUT_NID,
6154 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6155 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006156 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006157 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6158 .channel_mode = alc882_3ST_6ch_modes,
6159 .need_dac_fix = 1,
6160 .input_mux = &alc882_capture_source,
6161 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006162 [ALC882_ASUS_A7M] = {
6163 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6164 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6165 alc880_gpio1_init_verbs,
6166 alc882_asus_a7m_verbs },
6167 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6168 .dac_nids = alc882_dac_nids,
6169 .dig_out_nid = ALC882_DIGOUT_NID,
6170 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6171 .channel_mode = alc880_threestack_modes,
6172 .need_dac_fix = 1,
6173 .input_mux = &alc882_capture_source,
6174 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006175};
6176
6177
6178/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006179 * Pin config fixes
6180 */
6181enum {
6182 PINFIX_ABIT_AW9D_MAX
6183};
6184
6185static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6186 { 0x15, 0x01080104 }, /* side */
6187 { 0x16, 0x01011012 }, /* rear */
6188 { 0x17, 0x01016011 }, /* clfe */
6189 { }
6190};
6191
6192static const struct alc_pincfg *alc882_pin_fixes[] = {
6193 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6194};
6195
6196static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6197 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6198 {}
6199};
6200
6201/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006202 * BIOS auto configuration
6203 */
6204static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6205 hda_nid_t nid, int pin_type,
6206 int dac_idx)
6207{
6208 /* set as output */
6209 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006210 int idx;
6211
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006212 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006213 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6214 idx = 4;
6215 else
6216 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006217 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6218
6219}
6220
6221static void alc882_auto_init_multi_out(struct hda_codec *codec)
6222{
6223 struct alc_spec *spec = codec->spec;
6224 int i;
6225
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006226 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006227 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006228 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006229 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006230 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006231 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006232 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006233 }
6234}
6235
6236static void alc882_auto_init_hp_out(struct hda_codec *codec)
6237{
6238 struct alc_spec *spec = codec->spec;
6239 hda_nid_t pin;
6240
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006241 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006242 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006243 /* use dac 0 */
6244 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006245 pin = spec->autocfg.speaker_pins[0];
6246 if (pin)
6247 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006248}
6249
6250#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6251#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6252
6253static void alc882_auto_init_analog_input(struct hda_codec *codec)
6254{
6255 struct alc_spec *spec = codec->spec;
6256 int i;
6257
6258 for (i = 0; i < AUTO_PIN_LAST; i++) {
6259 hda_nid_t nid = spec->autocfg.input_pins[i];
6260 if (alc882_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006261 snd_hda_codec_write(codec, nid, 0,
6262 AC_VERB_SET_PIN_WIDGET_CONTROL,
6263 i <= AUTO_PIN_FRONT_MIC ?
6264 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01006265 if (nid != ALC882_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006266 snd_hda_codec_write(codec, nid, 0,
6267 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006268 AMP_OUT_MUTE);
6269 }
6270 }
6271}
6272
Takashi Iwai776e1842007-08-29 15:07:11 +02006273/* add mic boosts if needed */
6274static int alc_auto_add_mic_boost(struct hda_codec *codec)
6275{
6276 struct alc_spec *spec = codec->spec;
6277 int err;
6278 hda_nid_t nid;
6279
6280 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006281 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006282 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6283 "Mic Boost",
6284 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6285 if (err < 0)
6286 return err;
6287 }
6288 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006289 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006290 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6291 "Front Mic Boost",
6292 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6293 if (err < 0)
6294 return err;
6295 }
6296 return 0;
6297}
6298
Kailang Yangdf694da2005-12-05 19:42:22 +01006299/* almost identical with ALC880 parser... */
6300static int alc882_parse_auto_config(struct hda_codec *codec)
6301{
6302 struct alc_spec *spec = codec->spec;
6303 int err = alc880_parse_auto_config(codec);
6304
6305 if (err < 0)
6306 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006307 else if (!err)
6308 return 0; /* no config found */
6309
6310 err = alc_auto_add_mic_boost(codec);
6311 if (err < 0)
6312 return err;
6313
6314 /* hack - override the init verbs */
6315 spec->init_verbs[0] = alc882_auto_init_verbs;
6316
6317 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006318}
6319
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006320/* additional initialization for auto-configuration model */
6321static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006322{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006323 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006324 alc882_auto_init_multi_out(codec);
6325 alc882_auto_init_hp_out(codec);
6326 alc882_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006327 if (spec->unsol_event)
6328 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006329}
6330
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331static int patch_alc882(struct hda_codec *codec)
6332{
6333 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006334 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006336 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 if (spec == NULL)
6338 return -ENOMEM;
6339
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 codec->spec = spec;
6341
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006342 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6343 alc882_models,
6344 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345
Kailang Yangdf694da2005-12-05 19:42:22 +01006346 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006347 /* Pick up systems that don't supply PCI SSID */
6348 switch (codec->subsystem_id) {
6349 case 0x106b0c00: /* Mac Pro */
6350 board_config = ALC885_MACPRO;
6351 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006352 case 0x106b1000: /* iMac 24 */
6353 board_config = ALC885_IMAC24;
6354 break;
Jiang zhe3d5fa2e2008-01-10 13:05:47 +01006355 case 0x106b00a1: /* Macbook */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006356 case 0x106b2c00: /* Macbook Pro rev3 */
6357 board_config = ALC885_MBP3;
6358 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006359 default:
6360 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6361 "trying auto-probe from BIOS...\n");
6362 board_config = ALC882_AUTO;
6363 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006364 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006365
Takashi Iwaif95474e2007-07-10 00:47:43 +02006366 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6367
Kailang Yangdf694da2005-12-05 19:42:22 +01006368 if (board_config == ALC882_AUTO) {
6369 /* automatic parse from the BIOS config */
6370 err = alc882_parse_auto_config(codec);
6371 if (err < 0) {
6372 alc_free(codec);
6373 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006374 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006375 printk(KERN_INFO
6376 "hda_codec: Cannot set up configuration "
6377 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006378 board_config = ALC882_3ST_DIG;
6379 }
6380 }
6381
6382 if (board_config != ALC882_AUTO)
6383 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384
6385 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006386 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6387 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006388 /* FIXME: setup DAC5 */
6389 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6390 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
6392 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006393 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6394 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006396 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006397 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006398 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006399 /* get type */
6400 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006401 if (wcap != AC_WID_AUD_IN) {
6402 spec->adc_nids = alc882_adc_nids_alt;
6403 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006404 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006405 spec->mixers[spec->num_mixers] =
6406 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006407 spec->num_mixers++;
6408 } else {
6409 spec->adc_nids = alc882_adc_nids;
6410 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006411 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006412 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6413 spec->num_mixers++;
6414 }
6415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416
Takashi Iwai2134ea42008-01-10 16:53:55 +01006417 spec->vmaster_nid = 0x0c;
6418
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006420 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006421 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006422#ifdef CONFIG_SND_HDA_POWER_SAVE
6423 if (!spec->loopback.amplist)
6424 spec->loopback.amplist = alc882_loopbacks;
6425#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426
6427 return 0;
6428}
6429
6430/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006431 * ALC883 support
6432 *
6433 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6434 * configuration. Each pin widget can choose any input DACs and a mixer.
6435 * Each ADC is connected from a mixer of all inputs. This makes possible
6436 * 6-channel independent captures.
6437 *
6438 * In addition, an independent DAC for the multi-playback (not used in this
6439 * driver yet).
6440 */
6441#define ALC883_DIGOUT_NID 0x06
6442#define ALC883_DIGIN_NID 0x0a
6443
6444static hda_nid_t alc883_dac_nids[4] = {
6445 /* front, rear, clfe, rear_surr */
6446 0x02, 0x04, 0x03, 0x05
6447};
6448
6449static hda_nid_t alc883_adc_nids[2] = {
6450 /* ADC1-2 */
6451 0x08, 0x09,
6452};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006453
Takashi Iwaie1406342008-02-11 18:32:32 +01006454static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6455
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006456/* input MUX */
6457/* FIXME: should be a matrix-type input source selection */
6458
6459static struct hda_input_mux alc883_capture_source = {
6460 .num_items = 4,
6461 .items = {
6462 { "Mic", 0x0 },
6463 { "Front Mic", 0x1 },
6464 { "Line", 0x2 },
6465 { "CD", 0x4 },
6466 },
6467};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006468
6469static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6470 .num_items = 2,
6471 .items = {
6472 { "Mic", 0x1 },
6473 { "Line", 0x2 },
6474 },
6475};
6476
Kailang Yang272a5272007-05-14 11:00:38 +02006477static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6478 .num_items = 4,
6479 .items = {
6480 { "Mic", 0x0 },
6481 { "iMic", 0x1 },
6482 { "Line", 0x2 },
6483 { "CD", 0x4 },
6484 },
6485};
6486
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006487#define alc883_mux_enum_info alc_mux_enum_info
6488#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006489/* ALC883 has the ALC882-type input selection */
6490#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006491
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006492/*
6493 * 2ch mode
6494 */
6495static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6496 { 2, NULL }
6497};
6498
6499/*
6500 * 2ch mode
6501 */
6502static struct hda_verb alc883_3ST_ch2_init[] = {
6503 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6504 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6505 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6506 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6507 { } /* end */
6508};
6509
6510/*
Tobin Davisb2011312007-09-17 12:45:11 +02006511 * 4ch mode
6512 */
6513static struct hda_verb alc883_3ST_ch4_init[] = {
6514 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6515 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6516 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6517 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6518 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6519 { } /* end */
6520};
6521
6522/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006523 * 6ch mode
6524 */
6525static struct hda_verb alc883_3ST_ch6_init[] = {
6526 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6527 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6528 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6529 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6530 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6531 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6532 { } /* end */
6533};
6534
Tobin Davisb2011312007-09-17 12:45:11 +02006535static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006536 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006537 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006538 { 6, alc883_3ST_ch6_init },
6539};
6540
6541/*
6542 * 6ch mode
6543 */
6544static struct hda_verb alc883_sixstack_ch6_init[] = {
6545 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6546 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6547 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6548 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6549 { } /* end */
6550};
6551
6552/*
6553 * 8ch mode
6554 */
6555static struct hda_verb alc883_sixstack_ch8_init[] = {
6556 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6557 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6558 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6559 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6560 { } /* end */
6561};
6562
6563static struct hda_channel_mode alc883_sixstack_modes[2] = {
6564 { 6, alc883_sixstack_ch6_init },
6565 { 8, alc883_sixstack_ch8_init },
6566};
6567
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006568static struct hda_verb alc883_medion_eapd_verbs[] = {
6569 /* eanable EAPD on medion laptop */
6570 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6571 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6572 { }
6573};
6574
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006575/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6576 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6577 */
6578
6579static struct snd_kcontrol_new alc883_base_mixer[] = {
6580 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6581 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6582 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6583 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6584 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6585 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6586 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6587 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6588 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6589 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6590 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6591 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6592 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6593 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6594 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6595 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006596 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006597 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6598 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006599 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006600 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6601 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6602 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6603 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6604 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6605 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6606 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6607 {
6608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6609 /* .name = "Capture Source", */
6610 .name = "Input Source",
6611 .count = 2,
6612 .info = alc883_mux_enum_info,
6613 .get = alc883_mux_enum_get,
6614 .put = alc883_mux_enum_put,
6615 },
6616 { } /* end */
6617};
6618
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006619static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6620 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6621 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6622 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6623 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6624 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6625 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6626 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6627 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6628 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6629 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6630 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6631 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6632 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6633 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6634 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6635 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6636 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6637 {
6638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6639 /* .name = "Capture Source", */
6640 .name = "Input Source",
6641 .count = 2,
6642 .info = alc883_mux_enum_info,
6643 .get = alc883_mux_enum_get,
6644 .put = alc883_mux_enum_put,
6645 },
6646 { } /* end */
6647};
6648
Jiang zhe368c7a92008-03-04 11:20:33 +01006649static struct snd_kcontrol_new alc883_clevo_m720r_mixer[] = {
6650 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6651 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
6652 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6653 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
6654 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6655 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6656 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6657 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6658 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6659 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6660 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6661 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6662 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6663 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6664 {
6665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6666 /* .name = "Capture Source", */
6667 .name = "Input Source",
6668 .count = 2,
6669 .info = alc883_mux_enum_info,
6670 .get = alc883_mux_enum_get,
6671 .put = alc883_mux_enum_put,
6672 },
6673 { } /* end */
6674};
6675
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006676static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6677 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6678 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6679 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6680 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6681 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6682 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6683 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6684 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006685 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006686 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6687 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006688 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006689 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6690 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6691 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6692 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6693 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6694 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6695 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6696 {
6697 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6698 /* .name = "Capture Source", */
6699 .name = "Input Source",
6700 .count = 2,
6701 .info = alc883_mux_enum_info,
6702 .get = alc883_mux_enum_get,
6703 .put = alc883_mux_enum_put,
6704 },
6705 { } /* end */
6706};
6707
6708static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6709 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6710 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6711 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6712 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6713 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6714 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6715 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6716 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6717 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6718 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6719 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6720 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6721 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6722 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006723 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006724 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6725 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006726 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006727 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6728 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6729 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6730 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6731 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6732 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6733 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6734 {
6735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6736 /* .name = "Capture Source", */
6737 .name = "Input Source",
6738 .count = 2,
6739 .info = alc883_mux_enum_info,
6740 .get = alc883_mux_enum_get,
6741 .put = alc883_mux_enum_put,
6742 },
6743 { } /* end */
6744};
6745
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006746static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006747 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6748 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6749 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6750 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6751 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6752 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6753 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6754 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6755 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
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),
Tobin Davisc07584c2006-10-13 12:32:16 +02006762 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6763 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006764 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006765 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6766 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6767 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6768 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6769 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6770
6771 {
6772 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6773 /* .name = "Capture Source", */
6774 .name = "Input Source",
6775 .count = 1,
6776 .info = alc883_mux_enum_info,
6777 .get = alc883_mux_enum_get,
6778 .put = alc883_mux_enum_put,
6779 },
6780 { } /* end */
6781};
6782
Kailang Yangccc656c2006-10-17 12:32:26 +02006783static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6784 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6785 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6786 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6787 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6788 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6789 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6790 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6791 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6792 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6793 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6794 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6795 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6796 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6797 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006798 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006799 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6800 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6801 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6802 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6803 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6804 {
6805 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6806 /* .name = "Capture Source", */
6807 .name = "Input Source",
6808 .count = 2,
6809 .info = alc883_mux_enum_info,
6810 .get = alc883_mux_enum_get,
6811 .put = alc883_mux_enum_put,
6812 },
6813 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006814};
Kailang Yangccc656c2006-10-17 12:32:26 +02006815
6816static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6817 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6818 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6819 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6820 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6821 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6822 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006823 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006824 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6825 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6826 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6827 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6828 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6829 {
6830 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6831 /* .name = "Capture Source", */
6832 .name = "Input Source",
6833 .count = 2,
6834 .info = alc883_mux_enum_info,
6835 .get = alc883_mux_enum_get,
6836 .put = alc883_mux_enum_put,
6837 },
6838 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006839};
Kailang Yangccc656c2006-10-17 12:32:26 +02006840
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006841static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6842 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6843 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006844 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6845 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006846 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6847 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6848 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6849 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6850 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6851 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6852 {
6853 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6854 /* .name = "Capture Source", */
6855 .name = "Input Source",
6856 .count = 1,
6857 .info = alc883_mux_enum_info,
6858 .get = alc883_mux_enum_get,
6859 .put = alc883_mux_enum_put,
6860 },
6861 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006862};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006863
Kailang Yang272a5272007-05-14 11:00:38 +02006864static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
6865 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6866 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
6867 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6868 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6869 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6870 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6871 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6872 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6873 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6874 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6875 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6876 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6877 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6878 {
6879 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6880 /* .name = "Capture Source", */
6881 .name = "Input Source",
6882 .count = 2,
6883 .info = alc883_mux_enum_info,
6884 .get = alc883_mux_enum_get,
6885 .put = alc883_mux_enum_put,
6886 },
6887 { } /* end */
6888};
6889
6890static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
6891 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6892 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6893 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6894 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6895 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6896 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6897 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6898 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6899 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6900 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6901 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6902 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6903 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6904 {
6905 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6906 /* .name = "Capture Source", */
6907 .name = "Input Source",
6908 .count = 2,
6909 .info = alc883_mux_enum_info,
6910 .get = alc883_mux_enum_get,
6911 .put = alc883_mux_enum_put,
6912 },
6913 { } /* end */
6914};
6915
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006916static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02006917 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6918 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6919 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6920 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6921 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6922 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6923 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6924 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6925 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6926 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6927 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6928 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6929 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6930 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6931 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6932 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6933 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6934 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6935 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6936 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6937 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6938 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6939 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6940 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6941 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6942 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6943 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6944 {
6945 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6946 /* .name = "Capture Source", */
6947 .name = "Input Source",
6948 .count = 2,
6949 .info = alc883_mux_enum_info,
6950 .get = alc883_mux_enum_get,
6951 .put = alc883_mux_enum_put,
6952 },
6953 { } /* end */
6954};
6955
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006956static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006957 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6958 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6959 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6960 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6961 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6962 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6963 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6964 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6965 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6966 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6967 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6968 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6969 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6970 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6971 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6972 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6973 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6974 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6975 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6976 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6977 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6978 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6979 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6980 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6981 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6982 {
6983 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6984 /* .name = "Capture Source", */
6985 .name = "Input Source",
6986 .count = 2,
6987 .info = alc883_mux_enum_info,
6988 .get = alc883_mux_enum_get,
6989 .put = alc883_mux_enum_put,
6990 },
6991 { } /* end */
6992};
6993
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01006994static struct snd_kcontrol_new alc888_6st_dell_mixer[] = {
6995 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6996 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6997 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6998 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6999 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
7000 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7001 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7002 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7003 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7004 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7005 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7006 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7007 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7008 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7009 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7010 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7011 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7012 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7013 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7014 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7015 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7016 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7017 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7018 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7019 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7020 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7021 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7022 {
7023 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7024 /* .name = "Capture Source", */
7025 .name = "Input Source",
7026 .count = 2,
7027 .info = alc883_mux_enum_info,
7028 .get = alc883_mux_enum_get,
7029 .put = alc883_mux_enum_put,
7030 },
7031 { } /* end */
7032};
7033
Tobin Davis2880a862007-08-07 11:50:26 +02007034static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007035 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7036 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007037 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007038 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7039 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007040 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7041 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7042 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007043 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7044 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7045 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7046 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7047 {
7048 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7049 /* .name = "Capture Source", */
7050 .name = "Input Source",
7051 .count = 2,
7052 .info = alc883_mux_enum_info,
7053 .get = alc883_mux_enum_get,
7054 .put = alc883_mux_enum_put,
7055 },
7056 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007057};
Tobin Davis2880a862007-08-07 11:50:26 +02007058
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007059static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7060 {
7061 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7062 .name = "Channel Mode",
7063 .info = alc_ch_mode_info,
7064 .get = alc_ch_mode_get,
7065 .put = alc_ch_mode_put,
7066 },
7067 { } /* end */
7068};
7069
7070static struct hda_verb alc883_init_verbs[] = {
7071 /* ADC1: mute amp left and right */
7072 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7073 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7074 /* ADC2: mute amp left and right */
7075 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7076 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7077 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7078 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7079 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7080 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7081 /* Rear mixer */
7082 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7083 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7084 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7085 /* CLFE mixer */
7086 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7087 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7088 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7089 /* Side mixer */
7090 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7091 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7092 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7093
Takashi Iwaicb53c622007-08-10 17:21:45 +02007094 /* mute analog input loopbacks */
7095 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7096 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7097 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7098 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007100
7101 /* Front Pin: output 0 (0x0c) */
7102 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7103 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7104 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7105 /* Rear Pin: output 1 (0x0d) */
7106 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7107 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7108 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7109 /* CLFE Pin: output 2 (0x0e) */
7110 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7111 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7112 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7113 /* Side Pin: output 3 (0x0f) */
7114 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7115 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7116 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7117 /* Mic (rear) pin: input vref at 80% */
7118 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7119 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7120 /* Front Mic pin: input vref at 80% */
7121 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7122 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7123 /* Line In pin: input */
7124 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7125 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7126 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7127 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7128 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7129 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7130 /* CD pin widget for input */
7131 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7132
7133 /* FIXME: use matrix-type input source selection */
7134 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7135 /* Input mixer2 */
7136 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7137 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7138 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7139 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7140 /* Input mixer3 */
7141 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7142 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7143 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7144 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7145 { }
7146};
7147
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007148/* toggle speaker-output according to the hp-jack state */
7149static void alc883_mitac_hp_automute(struct hda_codec *codec)
7150{
7151 unsigned int present;
7152
7153 present = snd_hda_codec_read(codec, 0x15, 0,
7154 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7155 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7156 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7157 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7158 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7159}
7160
7161/* auto-toggle front mic */
7162/*
7163static void alc883_mitac_mic_automute(struct hda_codec *codec)
7164{
7165 unsigned int present;
7166 unsigned char bits;
7167
7168 present = snd_hda_codec_read(codec, 0x18, 0,
7169 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7170 bits = present ? HDA_AMP_MUTE : 0;
7171 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7172}
7173*/
7174
7175static void alc883_mitac_automute(struct hda_codec *codec)
7176{
7177 alc883_mitac_hp_automute(codec);
7178 /* alc883_mitac_mic_automute(codec); */
7179}
7180
7181static void alc883_mitac_unsol_event(struct hda_codec *codec,
7182 unsigned int res)
7183{
7184 switch (res >> 26) {
7185 case ALC880_HP_EVENT:
7186 alc883_mitac_hp_automute(codec);
7187 break;
7188 case ALC880_MIC_EVENT:
7189 /* alc883_mitac_mic_automute(codec); */
7190 break;
7191 }
7192}
7193
7194static struct hda_verb alc883_mitac_verbs[] = {
7195 /* HP */
7196 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7197 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7198 /* Subwoofer */
7199 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7200 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7201
7202 /* enable unsolicited event */
7203 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7204 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7205
7206 { } /* end */
7207};
7208
Jiang zhe368c7a92008-03-04 11:20:33 +01007209static struct hda_verb alc883_clevo_m720r_verbs[] = {
7210 /* HP */
7211 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7212 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7213 /* Int speaker */
7214 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7215 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7216
7217 /* enable unsolicited event */
7218 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7219
7220 { } /* end */
7221};
7222
Kailang Yangccc656c2006-10-17 12:32:26 +02007223static struct hda_verb alc883_tagra_verbs[] = {
7224 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7225 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7226
7227 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7228 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7229
7230 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7231 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7232 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7233
7234 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007235 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7236 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7237 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007238
7239 { } /* end */
7240};
7241
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007242static struct hda_verb alc883_lenovo_101e_verbs[] = {
7243 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7244 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7245 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7246 { } /* end */
7247};
7248
Kailang Yang272a5272007-05-14 11:00:38 +02007249static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7250 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7251 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7252 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7253 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7254 { } /* end */
7255};
7256
7257static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7258 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7259 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7260 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7261 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7262 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7263 { } /* end */
7264};
7265
Kailang Yang189609a2007-08-20 11:31:23 +02007266static struct hda_verb alc883_haier_w66_verbs[] = {
7267 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7268 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7269
7270 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7271
7272 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7273 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7274 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7275 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7276 { } /* end */
7277};
7278
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007279static struct hda_verb alc888_6st_hp_verbs[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007280 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7281 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */
7282 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 1 (0x0d) */
7283 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7284 { }
7285};
7286
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007287static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007288 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7289 {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7290 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
7291 { }
7292};
7293
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007294static struct hda_verb alc888_6st_dell_verbs[] = {
7295 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7296 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 1 (0x0e) */
7297 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 2 (0x0d) */
7298 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7299 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7300 { }
7301};
7302
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007303static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007304 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7305 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7306 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7307 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7308 { }
7309};
7310
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007311static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007312 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7313 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7314 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7315 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7316 { }
7317};
7318
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007319static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7320 { 2, alc888_3st_hp_2ch_init },
7321 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007322};
7323
Kailang Yang272a5272007-05-14 11:00:38 +02007324/* toggle front-jack and RCA according to the hp-jack state */
7325static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7326{
7327 unsigned int present;
7328
7329 present = snd_hda_codec_read(codec, 0x1b, 0,
7330 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007331 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7332 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7333 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7334 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007335}
7336
7337/* toggle RCA according to the front-jack state */
7338static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7339{
7340 unsigned int present;
7341
7342 present = snd_hda_codec_read(codec, 0x14, 0,
7343 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007344 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7345 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007346}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007347
Kailang Yang272a5272007-05-14 11:00:38 +02007348static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7349 unsigned int res)
7350{
7351 if ((res >> 26) == ALC880_HP_EVENT)
7352 alc888_lenovo_ms7195_front_automute(codec);
7353 if ((res >> 26) == ALC880_FRONT_EVENT)
7354 alc888_lenovo_ms7195_rca_automute(codec);
7355}
7356
7357static struct hda_verb alc883_medion_md2_verbs[] = {
7358 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7359 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7360
7361 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7362
7363 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7364 { } /* end */
7365};
7366
7367/* toggle speaker-output according to the hp-jack state */
7368static void alc883_medion_md2_automute(struct hda_codec *codec)
7369{
7370 unsigned int present;
7371
7372 present = snd_hda_codec_read(codec, 0x14, 0,
7373 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007374 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7375 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007376}
7377
7378static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7379 unsigned int res)
7380{
7381 if ((res >> 26) == ALC880_HP_EVENT)
7382 alc883_medion_md2_automute(codec);
7383}
7384
Kailang Yangccc656c2006-10-17 12:32:26 +02007385/* toggle speaker-output according to the hp-jack state */
7386static void alc883_tagra_automute(struct hda_codec *codec)
7387{
7388 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007389 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007390
7391 present = snd_hda_codec_read(codec, 0x14, 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, 0x1b, HDA_OUTPUT, 0,
7395 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007396 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7397 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007398}
7399
7400static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7401{
7402 if ((res >> 26) == ALC880_HP_EVENT)
7403 alc883_tagra_automute(codec);
7404}
7405
Jiang zhe368c7a92008-03-04 11:20:33 +01007406/* toggle speaker-output according to the hp-jack state */
7407static void alc883_clevo_m720r_automute(struct hda_codec *codec)
7408{
7409 unsigned int present;
7410 unsigned char bits;
7411
7412 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7413 & AC_PINSENSE_PRESENCE;
7414 bits = present ? HDA_AMP_MUTE : 0;
7415 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7416 HDA_AMP_MUTE, bits);
7417}
7418
7419static void alc883_clevo_m720r_unsol_event(struct hda_codec *codec,
7420 unsigned int res)
7421{
7422 if ((res >> 26) == ALC880_HP_EVENT)
7423 alc883_clevo_m720r_automute(codec);
7424}
7425
Kailang Yang189609a2007-08-20 11:31:23 +02007426static void alc883_haier_w66_automute(struct hda_codec *codec)
7427{
7428 unsigned int present;
7429 unsigned char bits;
7430
7431 present = snd_hda_codec_read(codec, 0x1b, 0,
7432 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7433 bits = present ? 0x80 : 0;
7434 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7435 0x80, bits);
7436}
7437
7438static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7439 unsigned int res)
7440{
7441 if ((res >> 26) == ALC880_HP_EVENT)
7442 alc883_haier_w66_automute(codec);
7443}
7444
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007445static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7446{
7447 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007448 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007449
7450 present = snd_hda_codec_read(codec, 0x14, 0,
7451 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007452 bits = present ? HDA_AMP_MUTE : 0;
7453 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7454 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007455}
7456
7457static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7458{
7459 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007460 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007461
7462 present = snd_hda_codec_read(codec, 0x1b, 0,
7463 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007464 bits = present ? HDA_AMP_MUTE : 0;
7465 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7466 HDA_AMP_MUTE, bits);
7467 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7468 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007469}
7470
7471static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7472 unsigned int res)
7473{
7474 if ((res >> 26) == ALC880_HP_EVENT)
7475 alc883_lenovo_101e_all_automute(codec);
7476 if ((res >> 26) == ALC880_FRONT_EVENT)
7477 alc883_lenovo_101e_ispeaker_automute(codec);
7478}
7479
Takashi Iwai676a9b52007-08-16 15:23:35 +02007480/* toggle speaker-output according to the hp-jack state */
7481static void alc883_acer_aspire_automute(struct hda_codec *codec)
7482{
7483 unsigned int present;
7484
7485 present = snd_hda_codec_read(codec, 0x14, 0,
7486 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7487 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7488 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7489 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7490 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7491}
7492
7493static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7494 unsigned int res)
7495{
7496 if ((res >> 26) == ALC880_HP_EVENT)
7497 alc883_acer_aspire_automute(codec);
7498}
7499
Kailang Yangd1a991a2007-08-15 16:21:59 +02007500static struct hda_verb alc883_acer_eapd_verbs[] = {
7501 /* HP Pin: output 0 (0x0c) */
7502 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7503 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7504 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7505 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007506 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7507 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007508 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007509 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7510 /* eanable EAPD on medion laptop */
7511 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7512 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007513 /* enable unsolicited event */
7514 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007515 { }
7516};
7517
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007518static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7519{
7520 unsigned int present;
7521
7522 present = snd_hda_codec_read(codec, 0x1b, 0,
7523 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7524 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7525 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7526 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7527 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7528 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7529 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7530 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7531 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7532}
7533
7534static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7535 unsigned int res)
7536{
7537 switch (res >> 26) {
7538 case ALC880_HP_EVENT:
7539 printk("hp_event\n");
7540 alc888_6st_dell_front_automute(codec);
7541 break;
7542 }
7543}
7544
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007545/*
7546 * generic initialization of ADC, input mixers and output mixers
7547 */
7548static struct hda_verb alc883_auto_init_verbs[] = {
7549 /*
7550 * Unmute ADC0-2 and set the default input to mic-in
7551 */
7552 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7553 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7554 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7555 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7556
Takashi Iwaicb53c622007-08-10 17:21:45 +02007557 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007558 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007559 * Note: PASD motherboards uses the Line In 2 as the input for
7560 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007561 */
7562 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007563 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7564 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7565 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7566 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7567 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007568
7569 /*
7570 * Set up output mixers (0x0c - 0x0f)
7571 */
7572 /* set vol=0 to output mixers */
7573 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7574 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7575 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7576 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7577 /* set up input amps for analog loopback */
7578 /* Amp Indices: DAC = 0, mixer = 1 */
7579 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7580 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7581 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7582 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7583 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7584 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7585 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7586 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7587 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7588 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7589
7590 /* FIXME: use matrix-type input source selection */
7591 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7592 /* Input mixer1 */
7593 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7594 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7595 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007596 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007597 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7598 /* Input mixer2 */
7599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7600 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7601 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007602 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007603 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007604
7605 { }
7606};
7607
7608/* capture mixer elements */
7609static struct snd_kcontrol_new alc883_capture_mixer[] = {
7610 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7611 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7612 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7613 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7614 {
7615 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7616 /* The multiple "Capture Source" controls confuse alsamixer
7617 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007618 */
7619 /* .name = "Capture Source", */
7620 .name = "Input Source",
7621 .count = 2,
7622 .info = alc882_mux_enum_info,
7623 .get = alc882_mux_enum_get,
7624 .put = alc882_mux_enum_put,
7625 },
7626 { } /* end */
7627};
7628
Takashi Iwaicb53c622007-08-10 17:21:45 +02007629#ifdef CONFIG_SND_HDA_POWER_SAVE
7630#define alc883_loopbacks alc880_loopbacks
7631#endif
7632
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007633/* pcm configuration: identiacal with ALC880 */
7634#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7635#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01007636#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007637#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7638#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7639
7640/*
7641 * configuration and preset
7642 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007643static const char *alc883_models[ALC883_MODEL_LAST] = {
7644 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7645 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7646 [ALC883_3ST_6ch] = "3stack-6ch",
7647 [ALC883_6ST_DIG] = "6stack-dig",
7648 [ALC883_TARGA_DIG] = "targa-dig",
7649 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007650 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007651 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007652 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007653 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007654 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007655 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007656 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7657 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007658 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007659 [ALC888_6ST_HP] = "6stack-hp",
7660 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007661 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007662 [ALC883_MITAC] = "mitac",
Jiang zhe368c7a92008-03-04 11:20:33 +01007663 [ALC883_CLEVO_M720R] = "clevo-m720r",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007664 [ALC883_AUTO] = "auto",
7665};
7666
7667static struct snd_pci_quirk alc883_cfg_tbl[] = {
7668 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007669 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7670 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7671 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7672 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007673 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02007674 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007675 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7676 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
7677 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
7678 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007679 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007680 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7681 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7682 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007683 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007684 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7685 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7686 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
7687 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01007688 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007689 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7690 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7691 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7692 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7693 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7694 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7695 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7696 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7697 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007698 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7699 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007700 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007701 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007702 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007703 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007704 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Jiang zhe368c7a92008-03-04 11:20:33 +01007705 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720R),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007706 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007707 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007708 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Kailang Yang272a5272007-05-14 11:00:38 +02007709 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007710 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007711 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7712 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007713 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01007714 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02007715 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007716 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007717 {}
7718};
7719
7720static struct alc_config_preset alc883_presets[] = {
7721 [ALC883_3ST_2ch_DIG] = {
7722 .mixers = { alc883_3ST_2ch_mixer },
7723 .init_verbs = { alc883_init_verbs },
7724 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7725 .dac_nids = alc883_dac_nids,
7726 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007727 .dig_in_nid = ALC883_DIGIN_NID,
7728 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7729 .channel_mode = alc883_3ST_2ch_modes,
7730 .input_mux = &alc883_capture_source,
7731 },
7732 [ALC883_3ST_6ch_DIG] = {
7733 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7734 .init_verbs = { alc883_init_verbs },
7735 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7736 .dac_nids = alc883_dac_nids,
7737 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007738 .dig_in_nid = ALC883_DIGIN_NID,
7739 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7740 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007741 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007742 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007743 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007744 [ALC883_3ST_6ch] = {
7745 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7746 .init_verbs = { alc883_init_verbs },
7747 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7748 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007749 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7750 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007751 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007752 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007753 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007754 [ALC883_6ST_DIG] = {
7755 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7756 .init_verbs = { alc883_init_verbs },
7757 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7758 .dac_nids = alc883_dac_nids,
7759 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007760 .dig_in_nid = ALC883_DIGIN_NID,
7761 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7762 .channel_mode = alc883_sixstack_modes,
7763 .input_mux = &alc883_capture_source,
7764 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007765 [ALC883_TARGA_DIG] = {
7766 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7767 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7768 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7769 .dac_nids = alc883_dac_nids,
7770 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007771 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7772 .channel_mode = alc883_3ST_6ch_modes,
7773 .need_dac_fix = 1,
7774 .input_mux = &alc883_capture_source,
7775 .unsol_event = alc883_tagra_unsol_event,
7776 .init_hook = alc883_tagra_automute,
7777 },
7778 [ALC883_TARGA_2ch_DIG] = {
7779 .mixers = { alc883_tagra_2ch_mixer},
7780 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7781 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7782 .dac_nids = alc883_dac_nids,
7783 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007784 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7785 .channel_mode = alc883_3ST_2ch_modes,
7786 .input_mux = &alc883_capture_source,
7787 .unsol_event = alc883_tagra_unsol_event,
7788 .init_hook = alc883_tagra_automute,
7789 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007790 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007791 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007792 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7793 * and the headphone jack. Turn this on and rely on the
7794 * standard mute methods whenever the user wants to turn
7795 * these outputs off.
7796 */
7797 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7798 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7799 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007800 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7801 .channel_mode = alc883_3ST_2ch_modes,
7802 .input_mux = &alc883_capture_source,
7803 },
Tobin Davis2880a862007-08-07 11:50:26 +02007804 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007805 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007806 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007807 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7808 .dac_nids = alc883_dac_nids,
7809 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02007810 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7811 .channel_mode = alc883_3ST_2ch_modes,
7812 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007813 .unsol_event = alc883_acer_aspire_unsol_event,
7814 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007815 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007816 [ALC883_MEDION] = {
7817 .mixers = { alc883_fivestack_mixer,
7818 alc883_chmode_mixer },
7819 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007820 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007821 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7822 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02007823 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7824 .channel_mode = alc883_sixstack_modes,
7825 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007826 },
Kailang Yang272a5272007-05-14 11:00:38 +02007827 [ALC883_MEDION_MD2] = {
7828 .mixers = { alc883_medion_md2_mixer},
7829 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7830 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7831 .dac_nids = alc883_dac_nids,
7832 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007833 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7834 .channel_mode = alc883_3ST_2ch_modes,
7835 .input_mux = &alc883_capture_source,
7836 .unsol_event = alc883_medion_md2_unsol_event,
7837 .init_hook = alc883_medion_md2_automute,
7838 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007839 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007840 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007841 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7842 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7843 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007844 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7845 .channel_mode = alc883_3ST_2ch_modes,
7846 .input_mux = &alc883_capture_source,
7847 },
Jiang zhe368c7a92008-03-04 11:20:33 +01007848 [ALC883_CLEVO_M720R] = {
7849 .mixers = { alc883_clevo_m720r_mixer },
7850 .init_verbs = { alc883_init_verbs, alc883_clevo_m720r_verbs },
7851 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7852 .dac_nids = alc883_dac_nids,
7853 .dig_out_nid = ALC883_DIGOUT_NID,
7854 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7855 .channel_mode = alc883_3ST_2ch_modes,
7856 .input_mux = &alc883_capture_source,
7857 .unsol_event = alc883_clevo_m720r_unsol_event,
7858 .init_hook = alc883_clevo_m720r_automute,
7859 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007860 [ALC883_LENOVO_101E_2ch] = {
7861 .mixers = { alc883_lenovo_101e_2ch_mixer},
7862 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7863 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7864 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007865 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7866 .channel_mode = alc883_3ST_2ch_modes,
7867 .input_mux = &alc883_lenovo_101e_capture_source,
7868 .unsol_event = alc883_lenovo_101e_unsol_event,
7869 .init_hook = alc883_lenovo_101e_all_automute,
7870 },
Kailang Yang272a5272007-05-14 11:00:38 +02007871 [ALC883_LENOVO_NB0763] = {
7872 .mixers = { alc883_lenovo_nb0763_mixer },
7873 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7874 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7875 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007876 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7877 .channel_mode = alc883_3ST_2ch_modes,
7878 .need_dac_fix = 1,
7879 .input_mux = &alc883_lenovo_nb0763_capture_source,
7880 .unsol_event = alc883_medion_md2_unsol_event,
7881 .init_hook = alc883_medion_md2_automute,
7882 },
7883 [ALC888_LENOVO_MS7195_DIG] = {
7884 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7885 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7886 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7887 .dac_nids = alc883_dac_nids,
7888 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007889 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7890 .channel_mode = alc883_3ST_6ch_modes,
7891 .need_dac_fix = 1,
7892 .input_mux = &alc883_capture_source,
7893 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7894 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007895 },
7896 [ALC883_HAIER_W66] = {
7897 .mixers = { alc883_tagra_2ch_mixer},
7898 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7899 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7900 .dac_nids = alc883_dac_nids,
7901 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02007902 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7903 .channel_mode = alc883_3ST_2ch_modes,
7904 .input_mux = &alc883_capture_source,
7905 .unsol_event = alc883_haier_w66_unsol_event,
7906 .init_hook = alc883_haier_w66_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02007907 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007908 [ALC888_6ST_HP] = {
7909 .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
7910 .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007911 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7912 .dac_nids = alc883_dac_nids,
7913 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007914 .dig_in_nid = ALC883_DIGIN_NID,
7915 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7916 .channel_mode = alc883_sixstack_modes,
7917 .input_mux = &alc883_capture_source,
7918 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007919 [ALC888_3ST_HP] = {
7920 .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
7921 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007922 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7923 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007924 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7925 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007926 .need_dac_fix = 1,
7927 .input_mux = &alc883_capture_source,
7928 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007929 [ALC888_6ST_DELL] = {
7930 .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer },
7931 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
7932 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7933 .dac_nids = alc883_dac_nids,
7934 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007935 .dig_in_nid = ALC883_DIGIN_NID,
7936 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7937 .channel_mode = alc883_sixstack_modes,
7938 .input_mux = &alc883_capture_source,
7939 .unsol_event = alc888_6st_dell_unsol_event,
7940 .init_hook = alc888_6st_dell_front_automute,
7941 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007942 [ALC883_MITAC] = {
7943 .mixers = { alc883_mitac_mixer },
7944 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
7945 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7946 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007947 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7948 .channel_mode = alc883_3ST_2ch_modes,
7949 .input_mux = &alc883_capture_source,
7950 .unsol_event = alc883_mitac_unsol_event,
7951 .init_hook = alc883_mitac_automute,
7952 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007953};
7954
7955
7956/*
7957 * BIOS auto configuration
7958 */
7959static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
7960 hda_nid_t nid, int pin_type,
7961 int dac_idx)
7962{
7963 /* set as output */
7964 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007965 int idx;
7966
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007967 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007968 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7969 idx = 4;
7970 else
7971 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007972 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7973
7974}
7975
7976static void alc883_auto_init_multi_out(struct hda_codec *codec)
7977{
7978 struct alc_spec *spec = codec->spec;
7979 int i;
7980
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007981 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007982 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007983 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007984 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007985 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007986 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007987 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007988 }
7989}
7990
7991static void alc883_auto_init_hp_out(struct hda_codec *codec)
7992{
7993 struct alc_spec *spec = codec->spec;
7994 hda_nid_t pin;
7995
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007996 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007997 if (pin) /* connect to front */
7998 /* use dac 0 */
7999 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008000 pin = spec->autocfg.speaker_pins[0];
8001 if (pin)
8002 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008003}
8004
8005#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8006#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8007
8008static void alc883_auto_init_analog_input(struct hda_codec *codec)
8009{
8010 struct alc_spec *spec = codec->spec;
8011 int i;
8012
8013 for (i = 0; i < AUTO_PIN_LAST; i++) {
8014 hda_nid_t nid = spec->autocfg.input_pins[i];
8015 if (alc883_is_input_pin(nid)) {
8016 snd_hda_codec_write(codec, nid, 0,
8017 AC_VERB_SET_PIN_WIDGET_CONTROL,
8018 (i <= AUTO_PIN_FRONT_MIC ?
8019 PIN_VREF80 : PIN_IN));
8020 if (nid != ALC883_PIN_CD_NID)
8021 snd_hda_codec_write(codec, nid, 0,
8022 AC_VERB_SET_AMP_GAIN_MUTE,
8023 AMP_OUT_MUTE);
8024 }
8025 }
8026}
8027
8028/* almost identical with ALC880 parser... */
8029static int alc883_parse_auto_config(struct hda_codec *codec)
8030{
8031 struct alc_spec *spec = codec->spec;
8032 int err = alc880_parse_auto_config(codec);
8033
8034 if (err < 0)
8035 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008036 else if (!err)
8037 return 0; /* no config found */
8038
8039 err = alc_auto_add_mic_boost(codec);
8040 if (err < 0)
8041 return err;
8042
8043 /* hack - override the init verbs */
8044 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008045 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
8046 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02008047
8048 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008049}
8050
8051/* additional initialization for auto-configuration model */
8052static void alc883_auto_init(struct hda_codec *codec)
8053{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008054 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008055 alc883_auto_init_multi_out(codec);
8056 alc883_auto_init_hp_out(codec);
8057 alc883_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008058 if (spec->unsol_event)
8059 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008060}
8061
8062static int patch_alc883(struct hda_codec *codec)
8063{
8064 struct alc_spec *spec;
8065 int err, board_config;
8066
8067 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8068 if (spec == NULL)
8069 return -ENOMEM;
8070
8071 codec->spec = spec;
8072
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008073 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8074 alc883_models,
8075 alc883_cfg_tbl);
8076 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008077 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8078 "trying auto-probe from BIOS...\n");
8079 board_config = ALC883_AUTO;
8080 }
8081
8082 if (board_config == ALC883_AUTO) {
8083 /* automatic parse from the BIOS config */
8084 err = alc883_parse_auto_config(codec);
8085 if (err < 0) {
8086 alc_free(codec);
8087 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008088 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008089 printk(KERN_INFO
8090 "hda_codec: Cannot set up configuration "
8091 "from BIOS. Using base mode...\n");
8092 board_config = ALC883_3ST_2ch_DIG;
8093 }
8094 }
8095
8096 if (board_config != ALC883_AUTO)
8097 setup_preset(spec, &alc883_presets[board_config]);
8098
8099 spec->stream_name_analog = "ALC883 Analog";
8100 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8101 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008102 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008103
8104 spec->stream_name_digital = "ALC883 Digital";
8105 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8106 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8107
Takashi Iwaie1406342008-02-11 18:32:32 +01008108 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8109 spec->adc_nids = alc883_adc_nids;
8110 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008111
Takashi Iwai2134ea42008-01-10 16:53:55 +01008112 spec->vmaster_nid = 0x0c;
8113
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008114 codec->patch_ops = alc_patch_ops;
8115 if (board_config == ALC883_AUTO)
8116 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02008117#ifdef CONFIG_SND_HDA_POWER_SAVE
8118 if (!spec->loopback.amplist)
8119 spec->loopback.amplist = alc883_loopbacks;
8120#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008121
8122 return 0;
8123}
8124
8125/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008126 * ALC262 support
8127 */
8128
8129#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8130#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8131
8132#define alc262_dac_nids alc260_dac_nids
8133#define alc262_adc_nids alc882_adc_nids
8134#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008135#define alc262_capsrc_nids alc882_capsrc_nids
8136#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008137
8138#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008139#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008140
8141static struct snd_kcontrol_new alc262_base_mixer[] = {
8142 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8143 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8144 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8145 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8146 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8147 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8148 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8149 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008150 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008151 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8152 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008153 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008154 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008155 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008156 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8157 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8158 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8159 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008160 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008161};
8162
Kailang Yangccc656c2006-10-17 12:32:26 +02008163static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8164 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8165 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8166 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8167 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8168 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8169 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8170 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8171 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008172 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008173 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8174 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008175 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008176 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008177 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008178 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8179 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8180 { } /* end */
8181};
8182
Takashi Iwaice875f02008-01-28 18:17:43 +01008183/* update HP, line and mono-out pins according to the master switch */
8184static void alc262_hp_master_update(struct hda_codec *codec)
8185{
8186 struct alc_spec *spec = codec->spec;
8187 int val = spec->master_sw;
8188
8189 /* HP & line-out */
8190 snd_hda_codec_write_cache(codec, 0x1b, 0,
8191 AC_VERB_SET_PIN_WIDGET_CONTROL,
8192 val ? PIN_HP : 0);
8193 snd_hda_codec_write_cache(codec, 0x15, 0,
8194 AC_VERB_SET_PIN_WIDGET_CONTROL,
8195 val ? PIN_HP : 0);
8196 /* mono (speaker) depending on the HP jack sense */
8197 val = val && !spec->jack_present;
8198 snd_hda_codec_write_cache(codec, 0x16, 0,
8199 AC_VERB_SET_PIN_WIDGET_CONTROL,
8200 val ? PIN_OUT : 0);
8201}
8202
8203static void alc262_hp_bpc_automute(struct hda_codec *codec)
8204{
8205 struct alc_spec *spec = codec->spec;
8206 unsigned int presence;
8207 presence = snd_hda_codec_read(codec, 0x1b, 0,
8208 AC_VERB_GET_PIN_SENSE, 0);
8209 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8210 alc262_hp_master_update(codec);
8211}
8212
8213static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8214{
8215 if ((res >> 26) != ALC880_HP_EVENT)
8216 return;
8217 alc262_hp_bpc_automute(codec);
8218}
8219
8220static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8221{
8222 struct alc_spec *spec = codec->spec;
8223 unsigned int presence;
8224 presence = snd_hda_codec_read(codec, 0x15, 0,
8225 AC_VERB_GET_PIN_SENSE, 0);
8226 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8227 alc262_hp_master_update(codec);
8228}
8229
8230static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8231 unsigned int res)
8232{
8233 if ((res >> 26) != ALC880_HP_EVENT)
8234 return;
8235 alc262_hp_wildwest_automute(codec);
8236}
8237
8238static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8239 struct snd_ctl_elem_value *ucontrol)
8240{
8241 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8242 struct alc_spec *spec = codec->spec;
8243 *ucontrol->value.integer.value = spec->master_sw;
8244 return 0;
8245}
8246
8247static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8248 struct snd_ctl_elem_value *ucontrol)
8249{
8250 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8251 struct alc_spec *spec = codec->spec;
8252 int val = !!*ucontrol->value.integer.value;
8253
8254 if (val == spec->master_sw)
8255 return 0;
8256 spec->master_sw = val;
8257 alc262_hp_master_update(codec);
8258 return 1;
8259}
8260
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008261static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008262 {
8263 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8264 .name = "Master Playback Switch",
8265 .info = snd_ctl_boolean_mono_info,
8266 .get = alc262_hp_master_sw_get,
8267 .put = alc262_hp_master_sw_put,
8268 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008269 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8270 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8271 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008272 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8273 HDA_OUTPUT),
8274 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8275 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008276 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8277 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008278 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008279 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8280 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008281 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008282 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8283 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8284 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8285 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8286 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8287 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8288 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8289 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8290 { } /* end */
8291};
8292
Kailang Yangcd7509a2007-01-26 18:33:17 +01008293static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008294 {
8295 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8296 .name = "Master Playback Switch",
8297 .info = snd_ctl_boolean_mono_info,
8298 .get = alc262_hp_master_sw_get,
8299 .put = alc262_hp_master_sw_put,
8300 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008301 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8302 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8303 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8304 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008305 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8306 HDA_OUTPUT),
8307 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8308 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008309 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8310 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008311 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008312 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8313 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8314 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8315 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8316 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8317 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8318 { } /* end */
8319};
8320
8321static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8322 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8323 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008324 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008325 { } /* end */
8326};
8327
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008328/* mute/unmute internal speaker according to the hp jack and mute state */
8329static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8330{
8331 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008332
8333 if (force || !spec->sense_updated) {
8334 unsigned int present;
8335 present = snd_hda_codec_read(codec, 0x15, 0,
8336 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008337 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008338 spec->sense_updated = 1;
8339 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008340 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8341 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008342}
8343
8344static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8345 unsigned int res)
8346{
8347 if ((res >> 26) != ALC880_HP_EVENT)
8348 return;
8349 alc262_hp_t5735_automute(codec, 1);
8350}
8351
8352static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8353{
8354 alc262_hp_t5735_automute(codec, 1);
8355}
8356
8357static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008358 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8359 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008360 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8361 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8362 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8363 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8364 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8365 { } /* end */
8366};
8367
8368static struct hda_verb alc262_hp_t5735_verbs[] = {
8369 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8370 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8371
8372 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8373 { }
8374};
8375
Kailang Yang8c427222008-01-10 13:03:59 +01008376static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01008377 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8378 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008379 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8380 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01008381 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8382 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8383 { } /* end */
8384};
8385
8386static struct hda_verb alc262_hp_rp5700_verbs[] = {
8387 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8388 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8389 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8390 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8391 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8392 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8393 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8394 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8395 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8396 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8397 {}
8398};
8399
8400static struct hda_input_mux alc262_hp_rp5700_capture_source = {
8401 .num_items = 1,
8402 .items = {
8403 { "Line", 0x1 },
8404 },
8405};
8406
Takashi Iwai0724ea22007-08-23 00:31:43 +02008407/* bind hp and internal speaker mute (with plug check) */
8408static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
8409 struct snd_ctl_elem_value *ucontrol)
8410{
8411 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8412 long *valp = ucontrol->value.integer.value;
8413 int change;
8414
8415 /* change hp mute */
8416 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
8417 HDA_AMP_MUTE,
8418 valp[0] ? 0 : HDA_AMP_MUTE);
8419 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
8420 HDA_AMP_MUTE,
8421 valp[1] ? 0 : HDA_AMP_MUTE);
8422 if (change) {
8423 /* change speaker according to HP jack state */
8424 struct alc_spec *spec = codec->spec;
8425 unsigned int mute;
8426 if (spec->jack_present)
8427 mute = HDA_AMP_MUTE;
8428 else
8429 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
8430 HDA_OUTPUT, 0);
8431 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8432 HDA_AMP_MUTE, mute);
8433 }
8434 return change;
8435}
Takashi Iwai5b319542007-07-26 11:49:22 +02008436
Kailang Yang272a5272007-05-14 11:00:38 +02008437static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02008438 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8439 {
8440 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8441 .name = "Master Playback Switch",
8442 .info = snd_hda_mixer_amp_switch_info,
8443 .get = snd_hda_mixer_amp_switch_get,
8444 .put = alc262_sony_master_sw_put,
8445 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8446 },
Kailang Yang272a5272007-05-14 11:00:38 +02008447 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8448 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8449 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8450 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8451 { } /* end */
8452};
8453
Kailang Yang83c34212007-07-05 11:43:05 +02008454static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8455 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8456 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8457 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8459 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8460 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8461 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8462 { } /* end */
8463};
Kailang Yang272a5272007-05-14 11:00:38 +02008464
Kailang Yangdf694da2005-12-05 19:42:22 +01008465#define alc262_capture_mixer alc882_capture_mixer
8466#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8467
8468/*
8469 * generic initialization of ADC, input mixers and output mixers
8470 */
8471static struct hda_verb alc262_init_verbs[] = {
8472 /*
8473 * Unmute ADC0-2 and set the default input to mic-in
8474 */
8475 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8476 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8477 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8478 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8479 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8480 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8481
Takashi Iwaicb53c622007-08-10 17:21:45 +02008482 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008483 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008484 * Note: PASD motherboards uses the Line In 2 as the input for
8485 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008486 */
8487 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008488 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8489 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8490 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8491 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8492 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008493
8494 /*
8495 * Set up output mixers (0x0c - 0x0e)
8496 */
8497 /* set vol=0 to output mixers */
8498 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8499 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8500 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8501 /* set up input amps for analog loopback */
8502 /* Amp Indices: DAC = 0, mixer = 1 */
8503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8504 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8505 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8506 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8507 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8508 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8509
8510 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8511 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8512 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8513 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8514 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8515 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8516
8517 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8519 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8520 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8521 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8522
8523 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8524 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8525
8526 /* FIXME: use matrix-type input source selection */
8527 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8528 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8529 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8530 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8531 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8532 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8533 /* Input mixer2 */
8534 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8535 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8536 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8537 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8538 /* Input mixer3 */
8539 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8540 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8541 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008542 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008543
8544 { }
8545};
8546
Kailang Yangccc656c2006-10-17 12:32:26 +02008547static struct hda_verb alc262_hippo_unsol_verbs[] = {
8548 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8549 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8550 {}
8551};
8552
8553static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8554 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8555 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8556 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8557
8558 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8559 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8560 {}
8561};
8562
Kailang Yang272a5272007-05-14 11:00:38 +02008563static struct hda_verb alc262_sony_unsol_verbs[] = {
8564 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8565 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8566 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8567
8568 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8569 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8570};
8571
Kailang Yangccc656c2006-10-17 12:32:26 +02008572/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008573static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008574{
8575 struct alc_spec *spec = codec->spec;
8576 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008577 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008578
Takashi Iwai5b319542007-07-26 11:49:22 +02008579 /* need to execute and sync at first */
8580 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8581 present = snd_hda_codec_read(codec, 0x15, 0,
8582 AC_VERB_GET_PIN_SENSE, 0);
8583 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008584 if (spec->jack_present) {
8585 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008586 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8587 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008588 } else {
8589 /* unmute internal speaker if necessary */
8590 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008591 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8592 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008593 }
8594}
8595
8596/* unsolicited event for HP jack sensing */
8597static void alc262_hippo_unsol_event(struct hda_codec *codec,
8598 unsigned int res)
8599{
8600 if ((res >> 26) != ALC880_HP_EVENT)
8601 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008602 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008603}
8604
Takashi Iwai5b319542007-07-26 11:49:22 +02008605static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008606{
Kailang Yangccc656c2006-10-17 12:32:26 +02008607 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008608 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008609
Takashi Iwai5b319542007-07-26 11:49:22 +02008610 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8611 present = snd_hda_codec_read(codec, 0x1b, 0,
8612 AC_VERB_GET_PIN_SENSE, 0);
8613 present = (present & 0x80000000) != 0;
8614 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008615 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008616 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8617 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008618 } else {
8619 /* unmute internal speaker if necessary */
8620 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008621 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8622 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008623 }
8624}
8625
8626/* unsolicited event for HP jack sensing */
8627static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8628 unsigned int res)
8629{
8630 if ((res >> 26) != ALC880_HP_EVENT)
8631 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008632 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008633}
8634
Takashi Iwai834be882006-03-01 14:16:17 +01008635/*
8636 * fujitsu model
8637 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
8638 */
8639
8640#define ALC_HP_EVENT 0x37
8641
8642static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8643 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8644 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8645 {}
8646};
8647
8648static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008649 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008650 .items = {
8651 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008652 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008653 { "CD", 0x4 },
8654 },
8655};
8656
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008657static struct hda_input_mux alc262_HP_capture_source = {
8658 .num_items = 5,
8659 .items = {
8660 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008661 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008662 { "Line", 0x2 },
8663 { "CD", 0x4 },
8664 { "AUX IN", 0x6 },
8665 },
8666};
8667
zhejiangaccbe492007-08-31 12:36:05 +02008668static struct hda_input_mux alc262_HP_D7000_capture_source = {
8669 .num_items = 4,
8670 .items = {
8671 { "Mic", 0x0 },
8672 { "Front Mic", 0x2 },
8673 { "Line", 0x1 },
8674 { "CD", 0x4 },
8675 },
8676};
8677
Takashi Iwai834be882006-03-01 14:16:17 +01008678/* mute/unmute internal speaker according to the hp jack and mute state */
8679static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8680{
8681 struct alc_spec *spec = codec->spec;
8682 unsigned int mute;
8683
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008684 if (force || !spec->sense_updated) {
Takashi Iwai834be882006-03-01 14:16:17 +01008685 unsigned int present;
8686 /* need to execute and sync at first */
8687 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
8688 present = snd_hda_codec_read(codec, 0x14, 0,
8689 AC_VERB_GET_PIN_SENSE, 0);
8690 spec->jack_present = (present & 0x80000000) != 0;
8691 spec->sense_updated = 1;
8692 }
8693 if (spec->jack_present) {
8694 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008695 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8696 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008697 } else {
8698 /* unmute internal speaker if necessary */
8699 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008700 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8701 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008702 }
8703}
8704
8705/* unsolicited event for HP jack sensing */
8706static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8707 unsigned int res)
8708{
8709 if ((res >> 26) != ALC_HP_EVENT)
8710 return;
8711 alc262_fujitsu_automute(codec, 1);
8712}
8713
8714/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008715static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8716 .ops = &snd_hda_bind_vol,
8717 .values = {
8718 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8719 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8720 0
8721 },
8722};
Takashi Iwai834be882006-03-01 14:16:17 +01008723
8724/* bind hp and internal speaker mute (with plug check) */
8725static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8726 struct snd_ctl_elem_value *ucontrol)
8727{
8728 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8729 long *valp = ucontrol->value.integer.value;
8730 int change;
8731
8732 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008733 HDA_AMP_MUTE,
8734 valp[0] ? 0 : HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008735 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008736 HDA_AMP_MUTE,
8737 valp[1] ? 0 : HDA_AMP_MUTE);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008738 if (change)
8739 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008740 return change;
8741}
8742
8743static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008744 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008745 {
8746 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8747 .name = "Master Playback Switch",
8748 .info = snd_hda_mixer_amp_switch_info,
8749 .get = snd_hda_mixer_amp_switch_get,
8750 .put = alc262_fujitsu_master_sw_put,
8751 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8752 },
8753 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8754 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8755 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8756 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8757 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008758 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8759 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8760 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008761 { } /* end */
8762};
8763
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008764/* additional init verbs for Benq laptops */
8765static struct hda_verb alc262_EAPD_verbs[] = {
8766 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8767 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8768 {}
8769};
8770
Kailang Yang83c34212007-07-05 11:43:05 +02008771static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8772 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8773 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8774
8775 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8776 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8777 {}
8778};
8779
Tobin Davisf651b502007-10-26 12:40:47 +02008780/* Samsung Q1 Ultra Vista model setup */
8781static struct snd_kcontrol_new alc262_ultra_mixer[] = {
8782 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8783 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8784 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8785 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8786 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8787 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8788 { } /* end */
8789};
8790
8791static struct hda_verb alc262_ultra_verbs[] = {
8792 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8793 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8794 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8795 /* Mic is on Node 0x19 */
8796 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8797 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
8798 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8799 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
8800 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8801 {0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
8802 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8803 {}
8804};
8805
8806static struct hda_input_mux alc262_ultra_capture_source = {
8807 .num_items = 1,
8808 .items = {
8809 { "Mic", 0x1 },
8810 },
8811};
8812
8813/* mute/unmute internal speaker according to the hp jack and mute state */
8814static void alc262_ultra_automute(struct hda_codec *codec)
8815{
8816 struct alc_spec *spec = codec->spec;
8817 unsigned int mute;
8818 unsigned int present;
8819
8820 /* need to execute and sync at first */
8821 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8822 present = snd_hda_codec_read(codec, 0x15, 0,
8823 AC_VERB_GET_PIN_SENSE, 0);
8824 spec->jack_present = (present & 0x80000000) != 0;
8825 if (spec->jack_present) {
8826 /* mute internal speaker */
8827 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8828 HDA_AMP_MUTE, HDA_AMP_MUTE);
8829 } else {
8830 /* unmute internal speaker if necessary */
8831 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
8832 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8833 HDA_AMP_MUTE, mute);
8834 }
8835}
8836
8837/* unsolicited event for HP jack sensing */
8838static void alc262_ultra_unsol_event(struct hda_codec *codec,
8839 unsigned int res)
8840{
8841 if ((res >> 26) != ALC880_HP_EVENT)
8842 return;
8843 alc262_ultra_automute(codec);
8844}
8845
Kailang Yangdf694da2005-12-05 19:42:22 +01008846/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008847static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
8848 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01008849{
8850 hda_nid_t nid;
8851 int err;
8852
8853 spec->multiout.num_dacs = 1; /* only use one dac */
8854 spec->multiout.dac_nids = spec->private_dac_nids;
8855 spec->multiout.dac_nids[0] = 2;
8856
8857 nid = cfg->line_out_pins[0];
8858 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008859 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8860 "Front Playback Volume",
8861 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
8862 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008863 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008864 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8865 "Front Playback Switch",
8866 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
8867 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008868 return err;
8869 }
8870
Takashi Iwai82bc9552006-03-21 11:24:42 +01008871 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008872 if (nid) {
8873 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008874 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8875 "Speaker Playback Volume",
8876 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8877 HDA_OUTPUT));
8878 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008879 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008880 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8881 "Speaker Playback Switch",
8882 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8883 HDA_OUTPUT));
8884 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008885 return err;
8886 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008887 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8888 "Speaker Playback Switch",
8889 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8890 HDA_OUTPUT));
8891 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008892 return err;
8893 }
8894 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008895 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008896 if (nid) {
8897 /* spec->multiout.hp_nid = 2; */
8898 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008899 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8900 "Headphone Playback Volume",
8901 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8902 HDA_OUTPUT));
8903 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008904 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008905 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8906 "Headphone Playback Switch",
8907 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8908 HDA_OUTPUT));
8909 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008910 return err;
8911 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008912 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8913 "Headphone Playback Switch",
8914 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8915 HDA_OUTPUT));
8916 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008917 return err;
8918 }
8919 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008920 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01008921}
8922
8923/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008924#define alc262_auto_create_analog_input_ctls \
8925 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01008926
8927/*
8928 * generic initialization of ADC, input mixers and output mixers
8929 */
8930static struct hda_verb alc262_volume_init_verbs[] = {
8931 /*
8932 * Unmute ADC0-2 and set the default input to mic-in
8933 */
8934 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8935 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8936 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8937 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8938 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8939 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8940
Takashi Iwaicb53c622007-08-10 17:21:45 +02008941 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008942 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008943 * Note: PASD motherboards uses the Line In 2 as the input for
8944 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008945 */
8946 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008947 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8948 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8949 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8950 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8951 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008952
8953 /*
8954 * Set up output mixers (0x0c - 0x0f)
8955 */
8956 /* set vol=0 to output mixers */
8957 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8958 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8959 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8960
8961 /* set up input amps for analog loopback */
8962 /* Amp Indices: DAC = 0, mixer = 1 */
8963 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8964 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8965 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8966 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8967 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8968 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8969
8970 /* FIXME: use matrix-type input source selection */
8971 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8972 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8973 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8974 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8975 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8976 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8977 /* Input mixer2 */
8978 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8979 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8980 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8981 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8982 /* Input mixer3 */
8983 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8984 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8985 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8986 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8987
8988 { }
8989};
8990
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008991static struct hda_verb alc262_HP_BPC_init_verbs[] = {
8992 /*
8993 * Unmute ADC0-2 and set the default input to mic-in
8994 */
8995 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8996 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8997 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8998 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8999 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9000 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9001
Takashi Iwaicb53c622007-08-10 17:21:45 +02009002 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009003 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009004 * Note: PASD motherboards uses the Line In 2 as the input for
9005 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009006 */
9007 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9014 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009015
9016 /*
9017 * Set up output mixers (0x0c - 0x0e)
9018 */
9019 /* set vol=0 to output mixers */
9020 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9021 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9022 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9023
9024 /* set up input amps for analog loopback */
9025 /* Amp Indices: DAC = 0, mixer = 1 */
9026 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9027 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9028 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9029 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9030 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9031 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9032
Takashi Iwaice875f02008-01-28 18:17:43 +01009033 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009034 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9035 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9036
9037 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9038 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9039
9040 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9041 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9042
9043 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9044 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9045 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9046 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9047 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
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
9057 /* FIXME: use matrix-type input source selection */
9058 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9059 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9060 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9061 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9062 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9063 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9064 /* Input mixer2 */
9065 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9066 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9067 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9068 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9069 /* Input mixer3 */
9070 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9071 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9072 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9073 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9074
Takashi Iwaice875f02008-01-28 18:17:43 +01009075 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9076
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009077 { }
9078};
9079
Kailang Yangcd7509a2007-01-26 18:33:17 +01009080static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
9081 /*
9082 * Unmute ADC0-2 and set the default input to mic-in
9083 */
9084 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9085 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9086 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9087 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9088 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9089 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9090
Takashi Iwaicb53c622007-08-10 17:21:45 +02009091 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01009092 * mixer widget
9093 * Note: PASD motherboards uses the Line In 2 as the input for front
9094 * panel mic (mic 2)
9095 */
9096 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009097 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9098 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9100 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9101 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9102 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9103 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9104 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01009105 /*
9106 * Set up output mixers (0x0c - 0x0e)
9107 */
9108 /* set vol=0 to output mixers */
9109 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9110 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9111 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9112
9113 /* set up input amps for analog loopback */
9114 /* Amp Indices: DAC = 0, mixer = 1 */
9115 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9116 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9117 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9118 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9119 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9120 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9121
9122
9123 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
9124 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
9125 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
9126 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
9127 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
9128 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
9129 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
9130
9131 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9132 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9133
9134 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9135 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9136
9137 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
9138 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9139 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9140 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9141 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9142 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9143
9144 /* FIXME: use matrix-type input source selection */
9145 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9146 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9147 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
9148 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
9149 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
9150 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
9151 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
9152 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9153 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
9154 /* Input mixer2 */
9155 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9156 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9157 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9158 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9159 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9160 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9161 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9162 /* Input mixer3 */
9163 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9164 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9165 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9166 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9167 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9168 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9169 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9170
Takashi Iwaice875f02008-01-28 18:17:43 +01009171 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9172
Kailang Yangcd7509a2007-01-26 18:33:17 +01009173 { }
9174};
9175
Takashi Iwaicb53c622007-08-10 17:21:45 +02009176#ifdef CONFIG_SND_HDA_POWER_SAVE
9177#define alc262_loopbacks alc880_loopbacks
9178#endif
9179
Kailang Yangdf694da2005-12-05 19:42:22 +01009180/* pcm configuration: identiacal with ALC880 */
9181#define alc262_pcm_analog_playback alc880_pcm_analog_playback
9182#define alc262_pcm_analog_capture alc880_pcm_analog_capture
9183#define alc262_pcm_digital_playback alc880_pcm_digital_playback
9184#define alc262_pcm_digital_capture alc880_pcm_digital_capture
9185
9186/*
9187 * BIOS auto configuration
9188 */
9189static int alc262_parse_auto_config(struct hda_codec *codec)
9190{
9191 struct alc_spec *spec = codec->spec;
9192 int err;
9193 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
9194
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009195 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9196 alc262_ignore);
9197 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009198 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009199 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01009200 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009201 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
9202 if (err < 0)
9203 return err;
9204 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
9205 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009206 return err;
9207
9208 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9209
9210 if (spec->autocfg.dig_out_pin)
9211 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
9212 if (spec->autocfg.dig_in_pin)
9213 spec->dig_in_nid = ALC262_DIGIN_NID;
9214
9215 if (spec->kctl_alloc)
9216 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9217
9218 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02009219 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01009220 spec->input_mux = &spec->private_imux;
9221
Takashi Iwai776e1842007-08-29 15:07:11 +02009222 err = alc_auto_add_mic_boost(codec);
9223 if (err < 0)
9224 return err;
9225
Kailang Yangdf694da2005-12-05 19:42:22 +01009226 return 1;
9227}
9228
9229#define alc262_auto_init_multi_out alc882_auto_init_multi_out
9230#define alc262_auto_init_hp_out alc882_auto_init_hp_out
9231#define alc262_auto_init_analog_input alc882_auto_init_analog_input
9232
9233
9234/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009235static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01009236{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009237 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01009238 alc262_auto_init_multi_out(codec);
9239 alc262_auto_init_hp_out(codec);
9240 alc262_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009241 if (spec->unsol_event)
9242 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01009243}
9244
9245/*
9246 * configuration and preset
9247 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009248static const char *alc262_models[ALC262_MODEL_LAST] = {
9249 [ALC262_BASIC] = "basic",
9250 [ALC262_HIPPO] = "hippo",
9251 [ALC262_HIPPO_1] = "hippo_1",
9252 [ALC262_FUJITSU] = "fujitsu",
9253 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01009254 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01009255 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +01009256 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009257 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02009258 [ALC262_BENQ_T31] = "benq-t31",
9259 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02009260 [ALC262_ULTRA] = "ultra",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009261 [ALC262_AUTO] = "auto",
9262};
9263
9264static struct snd_pci_quirk alc262_cfg_tbl[] = {
9265 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
9266 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009267 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009268 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
9269 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009270 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009271 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009272 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009273 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009274 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009275 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009276 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009277 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009278 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009279 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009280 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009281 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009282 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
9283 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
9284 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009285 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
9286 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +01009287 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009288 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009289 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009290 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9291 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9292 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009293 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +01009294 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009295 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009296 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02009297 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009298 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01009299 {}
9300};
9301
9302static struct alc_config_preset alc262_presets[] = {
9303 [ALC262_BASIC] = {
9304 .mixers = { alc262_base_mixer },
9305 .init_verbs = { alc262_init_verbs },
9306 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9307 .dac_nids = alc262_dac_nids,
9308 .hp_nid = 0x03,
9309 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9310 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01009311 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01009312 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009313 [ALC262_HIPPO] = {
9314 .mixers = { alc262_base_mixer },
9315 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
9316 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9317 .dac_nids = alc262_dac_nids,
9318 .hp_nid = 0x03,
9319 .dig_out_nid = ALC262_DIGOUT_NID,
9320 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9321 .channel_mode = alc262_modes,
9322 .input_mux = &alc262_capture_source,
9323 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009324 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009325 },
9326 [ALC262_HIPPO_1] = {
9327 .mixers = { alc262_hippo1_mixer },
9328 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
9329 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9330 .dac_nids = alc262_dac_nids,
9331 .hp_nid = 0x02,
9332 .dig_out_nid = ALC262_DIGOUT_NID,
9333 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9334 .channel_mode = alc262_modes,
9335 .input_mux = &alc262_capture_source,
9336 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009337 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009338 },
Takashi Iwai834be882006-03-01 14:16:17 +01009339 [ALC262_FUJITSU] = {
9340 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009341 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9342 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01009343 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9344 .dac_nids = alc262_dac_nids,
9345 .hp_nid = 0x03,
9346 .dig_out_nid = ALC262_DIGOUT_NID,
9347 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9348 .channel_mode = alc262_modes,
9349 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009350 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwai834be882006-03-01 14:16:17 +01009351 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009352 [ALC262_HP_BPC] = {
9353 .mixers = { alc262_HP_BPC_mixer },
9354 .init_verbs = { alc262_HP_BPC_init_verbs },
9355 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9356 .dac_nids = alc262_dac_nids,
9357 .hp_nid = 0x03,
9358 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9359 .channel_mode = alc262_modes,
9360 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009361 .unsol_event = alc262_hp_bpc_unsol_event,
9362 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009363 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009364 [ALC262_HP_BPC_D7000_WF] = {
9365 .mixers = { alc262_HP_BPC_WildWest_mixer },
9366 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9367 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9368 .dac_nids = alc262_dac_nids,
9369 .hp_nid = 0x03,
9370 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9371 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009372 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009373 .unsol_event = alc262_hp_wildwest_unsol_event,
9374 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009375 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009376 [ALC262_HP_BPC_D7000_WL] = {
9377 .mixers = { alc262_HP_BPC_WildWest_mixer,
9378 alc262_HP_BPC_WildWest_option_mixer },
9379 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9380 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9381 .dac_nids = alc262_dac_nids,
9382 .hp_nid = 0x03,
9383 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9384 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009385 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009386 .unsol_event = alc262_hp_wildwest_unsol_event,
9387 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009388 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009389 [ALC262_HP_TC_T5735] = {
9390 .mixers = { alc262_hp_t5735_mixer },
9391 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
9392 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9393 .dac_nids = alc262_dac_nids,
9394 .hp_nid = 0x03,
9395 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9396 .channel_mode = alc262_modes,
9397 .input_mux = &alc262_capture_source,
9398 .unsol_event = alc262_hp_t5735_unsol_event,
9399 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +01009400 },
9401 [ALC262_HP_RP5700] = {
9402 .mixers = { alc262_hp_rp5700_mixer },
9403 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
9404 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9405 .dac_nids = alc262_dac_nids,
9406 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9407 .channel_mode = alc262_modes,
9408 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009409 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009410 [ALC262_BENQ_ED8] = {
9411 .mixers = { alc262_base_mixer },
9412 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
9413 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9414 .dac_nids = alc262_dac_nids,
9415 .hp_nid = 0x03,
9416 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9417 .channel_mode = alc262_modes,
9418 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009419 },
Kailang Yang272a5272007-05-14 11:00:38 +02009420 [ALC262_SONY_ASSAMD] = {
9421 .mixers = { alc262_sony_mixer },
9422 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
9423 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9424 .dac_nids = alc262_dac_nids,
9425 .hp_nid = 0x02,
9426 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9427 .channel_mode = alc262_modes,
9428 .input_mux = &alc262_capture_source,
9429 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009430 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02009431 },
9432 [ALC262_BENQ_T31] = {
9433 .mixers = { alc262_benq_t31_mixer },
9434 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
9435 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9436 .dac_nids = alc262_dac_nids,
9437 .hp_nid = 0x03,
9438 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9439 .channel_mode = alc262_modes,
9440 .input_mux = &alc262_capture_source,
9441 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009442 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02009443 },
Tobin Davisf651b502007-10-26 12:40:47 +02009444 [ALC262_ULTRA] = {
9445 .mixers = { alc262_ultra_mixer },
9446 .init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
9447 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9448 .dac_nids = alc262_dac_nids,
9449 .hp_nid = 0x03,
9450 .dig_out_nid = ALC262_DIGOUT_NID,
9451 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9452 .channel_mode = alc262_modes,
9453 .input_mux = &alc262_ultra_capture_source,
9454 .unsol_event = alc262_ultra_unsol_event,
9455 .init_hook = alc262_ultra_automute,
9456 },
Kailang Yangdf694da2005-12-05 19:42:22 +01009457};
9458
9459static int patch_alc262(struct hda_codec *codec)
9460{
9461 struct alc_spec *spec;
9462 int board_config;
9463 int err;
9464
Robert P. J. Daydc041e02006-12-19 14:44:15 +01009465 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01009466 if (spec == NULL)
9467 return -ENOMEM;
9468
9469 codec->spec = spec;
9470#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009471 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
9472 * under-run
9473 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009474 {
9475 int tmp;
9476 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9477 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
9478 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9479 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9480 }
9481#endif
9482
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009483 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9484 alc262_models,
9485 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009486
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009487 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009488 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9489 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009490 board_config = ALC262_AUTO;
9491 }
9492
9493 if (board_config == ALC262_AUTO) {
9494 /* automatic parse from the BIOS config */
9495 err = alc262_parse_auto_config(codec);
9496 if (err < 0) {
9497 alc_free(codec);
9498 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009499 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009500 printk(KERN_INFO
9501 "hda_codec: Cannot set up configuration "
9502 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009503 board_config = ALC262_BASIC;
9504 }
9505 }
9506
9507 if (board_config != ALC262_AUTO)
9508 setup_preset(spec, &alc262_presets[board_config]);
9509
9510 spec->stream_name_analog = "ALC262 Analog";
9511 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9512 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9513
9514 spec->stream_name_digital = "ALC262 Digital";
9515 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9516 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9517
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009518 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009519 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009520 unsigned int wcap = get_wcaps(codec, 0x07);
9521
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009522 /* get type */
9523 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009524 if (wcap != AC_WID_AUD_IN) {
9525 spec->adc_nids = alc262_adc_nids_alt;
9526 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +01009527 spec->capsrc_nids = alc262_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009528 spec->mixers[spec->num_mixers] =
9529 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009530 spec->num_mixers++;
9531 } else {
9532 spec->adc_nids = alc262_adc_nids;
9533 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +01009534 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01009535 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9536 spec->num_mixers++;
9537 }
9538 }
9539
Takashi Iwai2134ea42008-01-10 16:53:55 +01009540 spec->vmaster_nid = 0x0c;
9541
Kailang Yangdf694da2005-12-05 19:42:22 +01009542 codec->patch_ops = alc_patch_ops;
9543 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009544 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009545#ifdef CONFIG_SND_HDA_POWER_SAVE
9546 if (!spec->loopback.amplist)
9547 spec->loopback.amplist = alc262_loopbacks;
9548#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009549
Kailang Yangdf694da2005-12-05 19:42:22 +01009550 return 0;
9551}
9552
Kailang Yangdf694da2005-12-05 19:42:22 +01009553/*
Kailang Yanga361d842007-06-05 12:30:55 +02009554 * ALC268 channel source setting (2 channel)
9555 */
9556#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9557#define alc268_modes alc260_modes
9558
9559static hda_nid_t alc268_dac_nids[2] = {
9560 /* front, hp */
9561 0x02, 0x03
9562};
9563
9564static hda_nid_t alc268_adc_nids[2] = {
9565 /* ADC0-1 */
9566 0x08, 0x07
9567};
9568
9569static hda_nid_t alc268_adc_nids_alt[1] = {
9570 /* ADC0 */
9571 0x08
9572};
9573
Takashi Iwaie1406342008-02-11 18:32:32 +01009574static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
9575
Kailang Yanga361d842007-06-05 12:30:55 +02009576static struct snd_kcontrol_new alc268_base_mixer[] = {
9577 /* output mixer control */
9578 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9579 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9580 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9581 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009582 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9583 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9584 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009585 { }
9586};
9587
Takashi Iwaiaef9d312008-02-19 13:16:41 +01009588/* bind Beep switches of both NID 0x0f and 0x10 */
9589static struct hda_bind_ctls alc268_bind_beep_sw = {
9590 .ops = &snd_hda_bind_sw,
9591 .values = {
9592 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
9593 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
9594 0
9595 },
9596};
9597
9598static struct snd_kcontrol_new alc268_beep_mixer[] = {
9599 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
9600 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
9601 { }
9602};
9603
Kailang Yangd1a991a2007-08-15 16:21:59 +02009604static struct hda_verb alc268_eapd_verbs[] = {
9605 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9606 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9607 { }
9608};
9609
Takashi Iwaid2738092007-08-16 14:59:45 +02009610/* Toshiba specific */
9611#define alc268_toshiba_automute alc262_hippo_automute
9612
9613static struct hda_verb alc268_toshiba_verbs[] = {
9614 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9615 { } /* end */
9616};
9617
9618/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009619/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009620static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9621 .ops = &snd_hda_bind_vol,
9622 .values = {
9623 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9624 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9625 0
9626 },
9627};
9628
Takashi Iwai889c4392007-08-23 18:56:52 +02009629/* mute/unmute internal speaker according to the hp jack and mute state */
9630static void alc268_acer_automute(struct hda_codec *codec, int force)
9631{
9632 struct alc_spec *spec = codec->spec;
9633 unsigned int mute;
9634
9635 if (force || !spec->sense_updated) {
9636 unsigned int present;
9637 present = snd_hda_codec_read(codec, 0x14, 0,
9638 AC_VERB_GET_PIN_SENSE, 0);
9639 spec->jack_present = (present & 0x80000000) != 0;
9640 spec->sense_updated = 1;
9641 }
9642 if (spec->jack_present)
9643 mute = HDA_AMP_MUTE; /* mute internal speaker */
9644 else /* unmute internal speaker if necessary */
9645 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9646 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9647 HDA_AMP_MUTE, mute);
9648}
9649
9650
9651/* bind hp and internal speaker mute (with plug check) */
9652static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9653 struct snd_ctl_elem_value *ucontrol)
9654{
9655 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9656 long *valp = ucontrol->value.integer.value;
9657 int change;
9658
9659 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9660 HDA_AMP_MUTE,
9661 valp[0] ? 0 : HDA_AMP_MUTE);
9662 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9663 HDA_AMP_MUTE,
9664 valp[1] ? 0 : HDA_AMP_MUTE);
9665 if (change)
9666 alc268_acer_automute(codec, 0);
9667 return change;
9668}
Takashi Iwaid2738092007-08-16 14:59:45 +02009669
9670static struct snd_kcontrol_new alc268_acer_mixer[] = {
9671 /* output mixer control */
9672 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9673 {
9674 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9675 .name = "Master Playback Switch",
9676 .info = snd_hda_mixer_amp_switch_info,
9677 .get = snd_hda_mixer_amp_switch_get,
9678 .put = alc268_acer_master_sw_put,
9679 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9680 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009681 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9682 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9683 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009684 { }
9685};
9686
9687static struct hda_verb alc268_acer_verbs[] = {
9688 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9689 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9690
9691 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9692 { }
9693};
9694
9695/* unsolicited event for HP jack sensing */
9696static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9697 unsigned int res)
9698{
Takashi Iwai889c4392007-08-23 18:56:52 +02009699 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009700 return;
9701 alc268_toshiba_automute(codec);
9702}
9703
9704static void alc268_acer_unsol_event(struct hda_codec *codec,
9705 unsigned int res)
9706{
Takashi Iwai889c4392007-08-23 18:56:52 +02009707 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009708 return;
9709 alc268_acer_automute(codec, 1);
9710}
9711
Takashi Iwai889c4392007-08-23 18:56:52 +02009712static void alc268_acer_init_hook(struct hda_codec *codec)
9713{
9714 alc268_acer_automute(codec, 1);
9715}
9716
Takashi Iwai3866f0b2008-01-15 12:37:42 +01009717static struct snd_kcontrol_new alc268_dell_mixer[] = {
9718 /* output mixer control */
9719 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9720 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9721 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9722 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9723 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9724 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9725 { }
9726};
9727
9728static struct hda_verb alc268_dell_verbs[] = {
9729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9730 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9731 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9732 { }
9733};
9734
9735/* mute/unmute internal speaker according to the hp jack and mute state */
9736static void alc268_dell_automute(struct hda_codec *codec)
9737{
9738 unsigned int present;
9739 unsigned int mute;
9740
9741 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
9742 if (present & 0x80000000)
9743 mute = HDA_AMP_MUTE;
9744 else
9745 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
9746 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9747 HDA_AMP_MUTE, mute);
9748}
9749
9750static void alc268_dell_unsol_event(struct hda_codec *codec,
9751 unsigned int res)
9752{
9753 if ((res >> 26) != ALC880_HP_EVENT)
9754 return;
9755 alc268_dell_automute(codec);
9756}
9757
9758#define alc268_dell_init_hook alc268_dell_automute
9759
Kailang Yanga361d842007-06-05 12:30:55 +02009760/*
9761 * generic initialization of ADC, input mixers and output mixers
9762 */
9763static struct hda_verb alc268_base_init_verbs[] = {
9764 /* Unmute DAC0-1 and set vol = 0 */
9765 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9766 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9767 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9768 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9769 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9770 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9771
9772 /*
9773 * Set up output mixers (0x0c - 0x0e)
9774 */
9775 /* set vol=0 to output mixers */
9776 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9777 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9778 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9779 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
9780
9781 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9782 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9783
9784 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9785 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9786 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9787 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9788 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9789 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9790 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9791 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9792
9793 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9794 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9795 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9796 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9797 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9798 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9799 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +01009800
9801 /* set PCBEEP vol = 0, mute connections */
9802 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9803 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9804 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +02009805
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009806 /* Unmute Selector 23h,24h and set the default input to mic-in */
9807
9808 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
9809 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9810 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
9811 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +02009812
Kailang Yanga361d842007-06-05 12:30:55 +02009813 { }
9814};
9815
9816/*
9817 * generic initialization of ADC, input mixers and output mixers
9818 */
9819static struct hda_verb alc268_volume_init_verbs[] = {
9820 /* set output DAC */
9821 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9822 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9823 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9824 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9825
9826 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9827 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9828 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9829 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9830 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9831
9832 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9833 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9834 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9835 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9836 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9837
9838 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9839 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9840 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9841 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9842
Takashi Iwaiaef9d312008-02-19 13:16:41 +01009843 /* set PCBEEP vol = 0, mute connections */
9844 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9845 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9846 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +02009847
9848 { }
9849};
9850
9851#define alc268_mux_enum_info alc_mux_enum_info
9852#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01009853#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +02009854
9855static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
9856 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9857 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9858 {
9859 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9860 /* The multiple "Capture Source" controls confuse alsamixer
9861 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +02009862 */
9863 /* .name = "Capture Source", */
9864 .name = "Input Source",
9865 .count = 1,
9866 .info = alc268_mux_enum_info,
9867 .get = alc268_mux_enum_get,
9868 .put = alc268_mux_enum_put,
9869 },
9870 { } /* end */
9871};
9872
9873static struct snd_kcontrol_new alc268_capture_mixer[] = {
9874 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9875 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9876 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
9877 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
9878 {
9879 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9880 /* The multiple "Capture Source" controls confuse alsamixer
9881 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +02009882 */
9883 /* .name = "Capture Source", */
9884 .name = "Input Source",
9885 .count = 2,
9886 .info = alc268_mux_enum_info,
9887 .get = alc268_mux_enum_get,
9888 .put = alc268_mux_enum_put,
9889 },
9890 { } /* end */
9891};
9892
9893static struct hda_input_mux alc268_capture_source = {
9894 .num_items = 4,
9895 .items = {
9896 { "Mic", 0x0 },
9897 { "Front Mic", 0x1 },
9898 { "Line", 0x2 },
9899 { "CD", 0x3 },
9900 },
9901};
9902
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009903#ifdef CONFIG_SND_DEBUG
9904static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009905 /* Volume widgets */
9906 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9907 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9908 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9909 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
9910 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
9911 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
9912 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
9913 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
9914 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
9915 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
9916 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
9917 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
9918 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +01009919 /* The below appears problematic on some hardwares */
9920 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009921 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9922 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
9923 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
9924 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
9925
9926 /* Modes for retasking pin widgets */
9927 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
9928 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
9929 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
9930 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
9931
9932 /* Controls for GPIO pins, assuming they are configured as outputs */
9933 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
9934 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
9935 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
9936 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
9937
9938 /* Switches to allow the digital SPDIF output pin to be enabled.
9939 * The ALC268 does not have an SPDIF input.
9940 */
9941 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
9942
9943 /* A switch allowing EAPD to be enabled. Some laptops seem to use
9944 * this output to turn on an external amplifier.
9945 */
9946 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
9947 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
9948
9949 { } /* end */
9950};
9951#endif
9952
Kailang Yanga361d842007-06-05 12:30:55 +02009953/* create input playback/capture controls for the given pin */
9954static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
9955 const char *ctlname, int idx)
9956{
9957 char name[32];
9958 int err;
9959
9960 sprintf(name, "%s Playback Volume", ctlname);
9961 if (nid == 0x14) {
9962 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9963 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
9964 HDA_OUTPUT));
9965 if (err < 0)
9966 return err;
9967 } else if (nid == 0x15) {
9968 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9969 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
9970 HDA_OUTPUT));
9971 if (err < 0)
9972 return err;
9973 } else
9974 return -1;
9975 sprintf(name, "%s Playback Switch", ctlname);
9976 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
9977 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
9978 if (err < 0)
9979 return err;
9980 return 0;
9981}
9982
9983/* add playback controls from the parsed DAC table */
9984static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
9985 const struct auto_pin_cfg *cfg)
9986{
9987 hda_nid_t nid;
9988 int err;
9989
9990 spec->multiout.num_dacs = 2; /* only use one dac */
9991 spec->multiout.dac_nids = spec->private_dac_nids;
9992 spec->multiout.dac_nids[0] = 2;
9993 spec->multiout.dac_nids[1] = 3;
9994
9995 nid = cfg->line_out_pins[0];
9996 if (nid)
9997 alc268_new_analog_output(spec, nid, "Front", 0);
9998
9999 nid = cfg->speaker_pins[0];
10000 if (nid == 0x1d) {
10001 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10002 "Speaker Playback Volume",
10003 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10004 if (err < 0)
10005 return err;
10006 }
10007 nid = cfg->hp_pins[0];
10008 if (nid)
10009 alc268_new_analog_output(spec, nid, "Headphone", 0);
10010
10011 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
10012 if (nid == 0x16) {
10013 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10014 "Mono Playback Switch",
10015 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
10016 if (err < 0)
10017 return err;
10018 }
10019 return 0;
10020}
10021
10022/* create playback/capture controls for input pins */
10023static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
10024 const struct auto_pin_cfg *cfg)
10025{
10026 struct hda_input_mux *imux = &spec->private_imux;
10027 int i, idx1;
10028
10029 for (i = 0; i < AUTO_PIN_LAST; i++) {
10030 switch(cfg->input_pins[i]) {
10031 case 0x18:
10032 idx1 = 0; /* Mic 1 */
10033 break;
10034 case 0x19:
10035 idx1 = 1; /* Mic 2 */
10036 break;
10037 case 0x1a:
10038 idx1 = 2; /* Line In */
10039 break;
10040 case 0x1c:
10041 idx1 = 3; /* CD */
10042 break;
10043 default:
10044 continue;
10045 }
10046 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
10047 imux->items[imux->num_items].index = idx1;
10048 imux->num_items++;
10049 }
10050 return 0;
10051}
10052
10053static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
10054{
10055 struct alc_spec *spec = codec->spec;
10056 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10057 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10058 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10059 unsigned int dac_vol1, dac_vol2;
10060
10061 if (speaker_nid) {
10062 snd_hda_codec_write(codec, speaker_nid, 0,
10063 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
10064 snd_hda_codec_write(codec, 0x0f, 0,
10065 AC_VERB_SET_AMP_GAIN_MUTE,
10066 AMP_IN_UNMUTE(1));
10067 snd_hda_codec_write(codec, 0x10, 0,
10068 AC_VERB_SET_AMP_GAIN_MUTE,
10069 AMP_IN_UNMUTE(1));
10070 } else {
10071 snd_hda_codec_write(codec, 0x0f, 0,
10072 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
10073 snd_hda_codec_write(codec, 0x10, 0,
10074 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
10075 }
10076
10077 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
10078 if (line_nid == 0x14)
10079 dac_vol2 = AMP_OUT_ZERO;
10080 else if (line_nid == 0x15)
10081 dac_vol1 = AMP_OUT_ZERO;
10082 if (hp_nid == 0x14)
10083 dac_vol2 = AMP_OUT_ZERO;
10084 else if (hp_nid == 0x15)
10085 dac_vol1 = AMP_OUT_ZERO;
10086 if (line_nid != 0x16 || hp_nid != 0x16 ||
10087 spec->autocfg.line_out_pins[1] != 0x16 ||
10088 spec->autocfg.line_out_pins[2] != 0x16)
10089 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
10090
10091 snd_hda_codec_write(codec, 0x02, 0,
10092 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
10093 snd_hda_codec_write(codec, 0x03, 0,
10094 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
10095}
10096
10097/* pcm configuration: identiacal with ALC880 */
10098#define alc268_pcm_analog_playback alc880_pcm_analog_playback
10099#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010010100#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020010101#define alc268_pcm_digital_playback alc880_pcm_digital_playback
10102
10103/*
10104 * BIOS auto configuration
10105 */
10106static int alc268_parse_auto_config(struct hda_codec *codec)
10107{
10108 struct alc_spec *spec = codec->spec;
10109 int err;
10110 static hda_nid_t alc268_ignore[] = { 0 };
10111
10112 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10113 alc268_ignore);
10114 if (err < 0)
10115 return err;
10116 if (!spec->autocfg.line_outs)
10117 return 0; /* can't find valid BIOS pin config */
10118
10119 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
10120 if (err < 0)
10121 return err;
10122 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
10123 if (err < 0)
10124 return err;
10125
10126 spec->multiout.max_channels = 2;
10127
10128 /* digital only support output */
10129 if (spec->autocfg.dig_out_pin)
10130 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
10131
10132 if (spec->kctl_alloc)
10133 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10134
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010135 if (spec->autocfg.speaker_pins[0] != 0x1d)
10136 spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
10137
Kailang Yanga361d842007-06-05 12:30:55 +020010138 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
10139 spec->num_mux_defs = 1;
10140 spec->input_mux = &spec->private_imux;
10141
Takashi Iwai776e1842007-08-29 15:07:11 +020010142 err = alc_auto_add_mic_boost(codec);
10143 if (err < 0)
10144 return err;
10145
Kailang Yanga361d842007-06-05 12:30:55 +020010146 return 1;
10147}
10148
10149#define alc268_auto_init_multi_out alc882_auto_init_multi_out
10150#define alc268_auto_init_hp_out alc882_auto_init_hp_out
10151#define alc268_auto_init_analog_input alc882_auto_init_analog_input
10152
10153/* init callback for auto-configuration model -- overriding the default init */
10154static void alc268_auto_init(struct hda_codec *codec)
10155{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010156 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020010157 alc268_auto_init_multi_out(codec);
10158 alc268_auto_init_hp_out(codec);
10159 alc268_auto_init_mono_speaker_out(codec);
10160 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010161 if (spec->unsol_event)
10162 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020010163}
10164
10165/*
10166 * configuration and preset
10167 */
10168static const char *alc268_models[ALC268_MODEL_LAST] = {
10169 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020010170 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020010171 [ALC268_ACER] = "acer",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010172 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010173 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010174#ifdef CONFIG_SND_DEBUG
10175 [ALC268_TEST] = "test",
10176#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010177 [ALC268_AUTO] = "auto",
10178};
10179
10180static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010181 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010010182 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010183 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010010184 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010185 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010186 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020010187 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020010188 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020010189 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020010190 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010191 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020010192 {}
10193};
10194
10195static struct alc_config_preset alc268_presets[] = {
10196 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010197 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10198 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020010199 .init_verbs = { alc268_base_init_verbs },
10200 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10201 .dac_nids = alc268_dac_nids,
10202 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10203 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010204 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020010205 .hp_nid = 0x03,
10206 .dig_out_nid = ALC268_DIGOUT_NID,
10207 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10208 .channel_mode = alc268_modes,
10209 .input_mux = &alc268_capture_source,
10210 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010211 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010212 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10213 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010214 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10215 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010216 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10217 .dac_nids = alc268_dac_nids,
10218 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10219 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010220 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010221 .hp_nid = 0x03,
10222 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10223 .channel_mode = alc268_modes,
10224 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010225 .unsol_event = alc268_toshiba_unsol_event,
10226 .init_hook = alc268_toshiba_automute,
10227 },
10228 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010229 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
10230 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010231 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10232 alc268_acer_verbs },
10233 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10234 .dac_nids = alc268_dac_nids,
10235 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10236 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010237 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020010238 .hp_nid = 0x02,
10239 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10240 .channel_mode = alc268_modes,
10241 .input_mux = &alc268_capture_source,
10242 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020010243 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010244 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010245 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010246 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010247 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10248 alc268_dell_verbs },
10249 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10250 .dac_nids = alc268_dac_nids,
10251 .hp_nid = 0x02,
10252 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10253 .channel_mode = alc268_modes,
10254 .unsol_event = alc268_dell_unsol_event,
10255 .init_hook = alc268_dell_init_hook,
10256 .input_mux = &alc268_capture_source,
10257 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010258 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010259 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10260 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010261 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10262 alc268_toshiba_verbs },
10263 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10264 .dac_nids = alc268_dac_nids,
10265 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10266 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010267 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010268 .hp_nid = 0x03,
10269 .dig_out_nid = ALC268_DIGOUT_NID,
10270 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10271 .channel_mode = alc268_modes,
10272 .input_mux = &alc268_capture_source,
10273 .unsol_event = alc268_toshiba_unsol_event,
10274 .init_hook = alc268_toshiba_automute
10275 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010276#ifdef CONFIG_SND_DEBUG
10277 [ALC268_TEST] = {
10278 .mixers = { alc268_test_mixer, alc268_capture_mixer },
10279 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10280 alc268_volume_init_verbs },
10281 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10282 .dac_nids = alc268_dac_nids,
10283 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10284 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010285 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010286 .hp_nid = 0x03,
10287 .dig_out_nid = ALC268_DIGOUT_NID,
10288 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10289 .channel_mode = alc268_modes,
10290 .input_mux = &alc268_capture_source,
10291 },
10292#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010293};
10294
10295static int patch_alc268(struct hda_codec *codec)
10296{
10297 struct alc_spec *spec;
10298 int board_config;
10299 int err;
10300
10301 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
10302 if (spec == NULL)
10303 return -ENOMEM;
10304
10305 codec->spec = spec;
10306
10307 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
10308 alc268_models,
10309 alc268_cfg_tbl);
10310
10311 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
10312 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
10313 "trying auto-probe from BIOS...\n");
10314 board_config = ALC268_AUTO;
10315 }
10316
10317 if (board_config == ALC268_AUTO) {
10318 /* automatic parse from the BIOS config */
10319 err = alc268_parse_auto_config(codec);
10320 if (err < 0) {
10321 alc_free(codec);
10322 return err;
10323 } else if (!err) {
10324 printk(KERN_INFO
10325 "hda_codec: Cannot set up configuration "
10326 "from BIOS. Using base mode...\n");
10327 board_config = ALC268_3ST;
10328 }
10329 }
10330
10331 if (board_config != ALC268_AUTO)
10332 setup_preset(spec, &alc268_presets[board_config]);
10333
10334 spec->stream_name_analog = "ALC268 Analog";
10335 spec->stream_analog_playback = &alc268_pcm_analog_playback;
10336 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010010337 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020010338
10339 spec->stream_name_digital = "ALC268 Digital";
10340 spec->stream_digital_playback = &alc268_pcm_digital_playback;
10341
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010342 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
10343 /* override the amp caps for beep generator */
10344 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
10345 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
10346 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
10347 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
10348 (0 << AC_AMPCAP_MUTE_SHIFT));
10349
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010350 if (!spec->adc_nids && spec->input_mux) {
10351 /* check whether NID 0x07 is valid */
10352 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010010353 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020010354
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010355 /* get type */
10356 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010010357 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010358 spec->adc_nids = alc268_adc_nids_alt;
10359 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
10360 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020010361 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010362 spec->num_mixers++;
10363 } else {
10364 spec->adc_nids = alc268_adc_nids;
10365 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
10366 spec->mixers[spec->num_mixers] =
10367 alc268_capture_mixer;
10368 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020010369 }
Takashi Iwaie1406342008-02-11 18:32:32 +010010370 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010010371 /* set default input source */
10372 for (i = 0; i < spec->num_adc_nids; i++)
10373 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
10374 0, AC_VERB_SET_CONNECT_SEL,
10375 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020010376 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010010377
10378 spec->vmaster_nid = 0x02;
10379
Kailang Yanga361d842007-06-05 12:30:55 +020010380 codec->patch_ops = alc_patch_ops;
10381 if (board_config == ALC268_AUTO)
10382 spec->init_hook = alc268_auto_init;
10383
10384 return 0;
10385}
10386
10387/*
Kailang Yangf6a92242007-12-13 16:52:54 +010010388 * ALC269 channel source setting (2 channel)
10389 */
10390#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
10391
10392#define alc269_dac_nids alc260_dac_nids
10393
10394static hda_nid_t alc269_adc_nids[1] = {
10395 /* ADC1 */
10396 0x07,
10397};
10398
10399#define alc269_modes alc260_modes
10400#define alc269_capture_source alc880_lg_lw_capture_source
10401
10402static struct snd_kcontrol_new alc269_base_mixer[] = {
10403 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10404 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10405 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10406 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10407 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10408 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10409 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10410 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10411 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10412 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10413 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10414 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
10415 { } /* end */
10416};
10417
10418/* capture mixer elements */
10419static struct snd_kcontrol_new alc269_capture_mixer[] = {
10420 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10421 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10422 {
10423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10424 /* The multiple "Capture Source" controls confuse alsamixer
10425 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010010426 */
10427 /* .name = "Capture Source", */
10428 .name = "Input Source",
10429 .count = 1,
10430 .info = alc_mux_enum_info,
10431 .get = alc_mux_enum_get,
10432 .put = alc_mux_enum_put,
10433 },
10434 { } /* end */
10435};
10436
10437/*
10438 * generic initialization of ADC, input mixers and output mixers
10439 */
10440static struct hda_verb alc269_init_verbs[] = {
10441 /*
10442 * Unmute ADC0 and set the default input to mic-in
10443 */
10444 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10445
10446 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
10447 * analog-loopback mixer widget
10448 * Note: PASD motherboards uses the Line In 2 as the input for
10449 * front panel mic (mic 2)
10450 */
10451 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
10452 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10453 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10454 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10455 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10456 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10457
10458 /*
10459 * Set up output mixers (0x0c - 0x0e)
10460 */
10461 /* set vol=0 to output mixers */
10462 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10463 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10464
10465 /* set up input amps for analog loopback */
10466 /* Amp Indices: DAC = 0, mixer = 1 */
10467 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10468 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10469 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10470 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10471 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10472 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10473
10474 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10475 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10476 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10477 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10478 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10479 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10480 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10481
10482 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10483 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10484 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10485 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10486 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10487 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10488 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10489
10490 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10491 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10492
10493 /* FIXME: use matrix-type input source selection */
10494 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
10495 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10496 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10497 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10498 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10499 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10500
10501 /* set EAPD */
10502 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10503 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10504 { }
10505};
10506
10507/* add playback controls from the parsed DAC table */
10508static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
10509 const struct auto_pin_cfg *cfg)
10510{
10511 hda_nid_t nid;
10512 int err;
10513
10514 spec->multiout.num_dacs = 1; /* only use one dac */
10515 spec->multiout.dac_nids = spec->private_dac_nids;
10516 spec->multiout.dac_nids[0] = 2;
10517
10518 nid = cfg->line_out_pins[0];
10519 if (nid) {
10520 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10521 "Front Playback Volume",
10522 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
10523 if (err < 0)
10524 return err;
10525 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10526 "Front Playback Switch",
10527 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10528 if (err < 0)
10529 return err;
10530 }
10531
10532 nid = cfg->speaker_pins[0];
10533 if (nid) {
10534 if (!cfg->line_out_pins[0]) {
10535 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10536 "Speaker Playback Volume",
10537 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10538 HDA_OUTPUT));
10539 if (err < 0)
10540 return err;
10541 }
10542 if (nid == 0x16) {
10543 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10544 "Speaker Playback Switch",
10545 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10546 HDA_OUTPUT));
10547 if (err < 0)
10548 return err;
10549 } else {
10550 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10551 "Speaker Playback Switch",
10552 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10553 HDA_OUTPUT));
10554 if (err < 0)
10555 return err;
10556 }
10557 }
10558 nid = cfg->hp_pins[0];
10559 if (nid) {
10560 /* spec->multiout.hp_nid = 2; */
10561 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
10562 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10563 "Headphone Playback Volume",
10564 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10565 HDA_OUTPUT));
10566 if (err < 0)
10567 return err;
10568 }
10569 if (nid == 0x16) {
10570 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10571 "Headphone Playback Switch",
10572 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10573 HDA_OUTPUT));
10574 if (err < 0)
10575 return err;
10576 } else {
10577 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10578 "Headphone Playback Switch",
10579 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10580 HDA_OUTPUT));
10581 if (err < 0)
10582 return err;
10583 }
10584 }
10585 return 0;
10586}
10587
10588#define alc269_auto_create_analog_input_ctls \
10589 alc880_auto_create_analog_input_ctls
10590
10591#ifdef CONFIG_SND_HDA_POWER_SAVE
10592#define alc269_loopbacks alc880_loopbacks
10593#endif
10594
10595/* pcm configuration: identiacal with ALC880 */
10596#define alc269_pcm_analog_playback alc880_pcm_analog_playback
10597#define alc269_pcm_analog_capture alc880_pcm_analog_capture
10598#define alc269_pcm_digital_playback alc880_pcm_digital_playback
10599#define alc269_pcm_digital_capture alc880_pcm_digital_capture
10600
10601/*
10602 * BIOS auto configuration
10603 */
10604static int alc269_parse_auto_config(struct hda_codec *codec)
10605{
10606 struct alc_spec *spec = codec->spec;
10607 int err;
10608 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
10609
10610 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10611 alc269_ignore);
10612 if (err < 0)
10613 return err;
10614
10615 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
10616 if (err < 0)
10617 return err;
10618 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
10619 if (err < 0)
10620 return err;
10621
10622 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10623
10624 if (spec->autocfg.dig_out_pin)
10625 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
10626
10627 if (spec->kctl_alloc)
10628 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10629
10630 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
10631 spec->num_mux_defs = 1;
10632 spec->input_mux = &spec->private_imux;
10633
10634 err = alc_auto_add_mic_boost(codec);
10635 if (err < 0)
10636 return err;
10637
10638 return 1;
10639}
10640
10641#define alc269_auto_init_multi_out alc882_auto_init_multi_out
10642#define alc269_auto_init_hp_out alc882_auto_init_hp_out
10643#define alc269_auto_init_analog_input alc882_auto_init_analog_input
10644
10645
10646/* init callback for auto-configuration model -- overriding the default init */
10647static void alc269_auto_init(struct hda_codec *codec)
10648{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010649 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010010650 alc269_auto_init_multi_out(codec);
10651 alc269_auto_init_hp_out(codec);
10652 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010653 if (spec->unsol_event)
10654 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010010655}
10656
10657/*
10658 * configuration and preset
10659 */
10660static const char *alc269_models[ALC269_MODEL_LAST] = {
10661 [ALC269_BASIC] = "basic",
10662};
10663
10664static struct snd_pci_quirk alc269_cfg_tbl[] = {
10665 {}
10666};
10667
10668static struct alc_config_preset alc269_presets[] = {
10669 [ALC269_BASIC] = {
10670 .mixers = { alc269_base_mixer },
10671 .init_verbs = { alc269_init_verbs },
10672 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
10673 .dac_nids = alc269_dac_nids,
10674 .hp_nid = 0x03,
10675 .num_channel_mode = ARRAY_SIZE(alc269_modes),
10676 .channel_mode = alc269_modes,
10677 .input_mux = &alc269_capture_source,
10678 },
10679};
10680
10681static int patch_alc269(struct hda_codec *codec)
10682{
10683 struct alc_spec *spec;
10684 int board_config;
10685 int err;
10686
10687 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10688 if (spec == NULL)
10689 return -ENOMEM;
10690
10691 codec->spec = spec;
10692
10693 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
10694 alc269_models,
10695 alc269_cfg_tbl);
10696
10697 if (board_config < 0) {
10698 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
10699 "trying auto-probe from BIOS...\n");
10700 board_config = ALC269_AUTO;
10701 }
10702
10703 if (board_config == ALC269_AUTO) {
10704 /* automatic parse from the BIOS config */
10705 err = alc269_parse_auto_config(codec);
10706 if (err < 0) {
10707 alc_free(codec);
10708 return err;
10709 } else if (!err) {
10710 printk(KERN_INFO
10711 "hda_codec: Cannot set up configuration "
10712 "from BIOS. Using base mode...\n");
10713 board_config = ALC269_BASIC;
10714 }
10715 }
10716
10717 if (board_config != ALC269_AUTO)
10718 setup_preset(spec, &alc269_presets[board_config]);
10719
10720 spec->stream_name_analog = "ALC269 Analog";
10721 spec->stream_analog_playback = &alc269_pcm_analog_playback;
10722 spec->stream_analog_capture = &alc269_pcm_analog_capture;
10723
10724 spec->stream_name_digital = "ALC269 Digital";
10725 spec->stream_digital_playback = &alc269_pcm_digital_playback;
10726 spec->stream_digital_capture = &alc269_pcm_digital_capture;
10727
10728 spec->adc_nids = alc269_adc_nids;
10729 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
10730 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
10731 spec->num_mixers++;
10732
10733 codec->patch_ops = alc_patch_ops;
10734 if (board_config == ALC269_AUTO)
10735 spec->init_hook = alc269_auto_init;
10736#ifdef CONFIG_SND_HDA_POWER_SAVE
10737 if (!spec->loopback.amplist)
10738 spec->loopback.amplist = alc269_loopbacks;
10739#endif
10740
10741 return 0;
10742}
10743
10744/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010745 * ALC861 channel source setting (2/6 channel selection for 3-stack)
10746 */
10747
10748/*
10749 * set the path ways for 2 channel output
10750 * need to set the codec line out and mic 1 pin widgets to inputs
10751 */
10752static struct hda_verb alc861_threestack_ch2_init[] = {
10753 /* set pin widget 1Ah (line in) for input */
10754 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010755 /* set pin widget 18h (mic1/2) for input, for mic also enable
10756 * the vref
10757 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010758 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10759
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010760 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10761#if 0
10762 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10763 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10764#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010765 { } /* end */
10766};
10767/*
10768 * 6ch mode
10769 * need to set the codec line out and mic 1 pin widgets to outputs
10770 */
10771static struct hda_verb alc861_threestack_ch6_init[] = {
10772 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10773 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10774 /* set pin widget 18h (mic1) for output (CLFE)*/
10775 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10776
10777 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010778 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010779
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010780 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10781#if 0
10782 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10783 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10784#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010785 { } /* end */
10786};
10787
10788static struct hda_channel_mode alc861_threestack_modes[2] = {
10789 { 2, alc861_threestack_ch2_init },
10790 { 6, alc861_threestack_ch6_init },
10791};
Takashi Iwai22309c32006-08-09 16:57:28 +020010792/* Set mic1 as input and unmute the mixer */
10793static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
10794 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10795 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10796 { } /* end */
10797};
10798/* Set mic1 as output and mute mixer */
10799static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
10800 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10801 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10802 { } /* end */
10803};
10804
10805static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
10806 { 2, alc861_uniwill_m31_ch2_init },
10807 { 4, alc861_uniwill_m31_ch4_init },
10808};
Kailang Yangdf694da2005-12-05 19:42:22 +010010809
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010810/* Set mic1 and line-in as input and unmute the mixer */
10811static struct hda_verb alc861_asus_ch2_init[] = {
10812 /* set pin widget 1Ah (line in) for input */
10813 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010814 /* set pin widget 18h (mic1/2) for input, for mic also enable
10815 * the vref
10816 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010817 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10818
10819 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10820#if 0
10821 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10822 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10823#endif
10824 { } /* end */
10825};
10826/* Set mic1 nad line-in as output and mute mixer */
10827static struct hda_verb alc861_asus_ch6_init[] = {
10828 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10829 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10830 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10831 /* set pin widget 18h (mic1) for output (CLFE)*/
10832 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10833 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10834 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
10835 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
10836
10837 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10838#if 0
10839 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10840 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10841#endif
10842 { } /* end */
10843};
10844
10845static struct hda_channel_mode alc861_asus_modes[2] = {
10846 { 2, alc861_asus_ch2_init },
10847 { 6, alc861_asus_ch6_init },
10848};
10849
Kailang Yangdf694da2005-12-05 19:42:22 +010010850/* patch-ALC861 */
10851
10852static struct snd_kcontrol_new alc861_base_mixer[] = {
10853 /* output mixer control */
10854 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10855 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10856 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10857 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10858 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10859
10860 /*Input mixer control */
10861 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10862 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10863 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10864 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10865 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10866 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10867 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10868 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10869 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10870 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010871
Kailang Yangdf694da2005-12-05 19:42:22 +010010872 /* Capture mixer control */
10873 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10874 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10875 {
10876 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10877 .name = "Capture Source",
10878 .count = 1,
10879 .info = alc_mux_enum_info,
10880 .get = alc_mux_enum_get,
10881 .put = alc_mux_enum_put,
10882 },
10883 { } /* end */
10884};
10885
10886static struct snd_kcontrol_new alc861_3ST_mixer[] = {
10887 /* output mixer control */
10888 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10889 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10890 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10891 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10892 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10893
10894 /* Input mixer control */
10895 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10896 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10897 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10898 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10899 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10900 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10901 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10902 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10903 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10904 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010905
Kailang Yangdf694da2005-12-05 19:42:22 +010010906 /* Capture mixer control */
10907 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10908 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10909 {
10910 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10911 .name = "Capture Source",
10912 .count = 1,
10913 .info = alc_mux_enum_info,
10914 .get = alc_mux_enum_get,
10915 .put = alc_mux_enum_put,
10916 },
10917 {
10918 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10919 .name = "Channel Mode",
10920 .info = alc_ch_mode_info,
10921 .get = alc_ch_mode_get,
10922 .put = alc_ch_mode_put,
10923 .private_value = ARRAY_SIZE(alc861_threestack_modes),
10924 },
10925 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010926};
10927
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010928static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010929 /* output mixer control */
10930 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10931 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10932 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10933
10934 /*Capture mixer control */
10935 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10936 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10937 {
10938 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10939 .name = "Capture Source",
10940 .count = 1,
10941 .info = alc_mux_enum_info,
10942 .get = alc_mux_enum_get,
10943 .put = alc_mux_enum_put,
10944 },
10945
10946 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010947};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010948
Takashi Iwai22309c32006-08-09 16:57:28 +020010949static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
10950 /* output mixer control */
10951 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10952 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10953 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10954 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10955 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10956
10957 /* Input mixer control */
10958 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10959 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10960 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10961 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10962 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10963 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10964 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10965 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10966 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10967 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010968
Takashi Iwai22309c32006-08-09 16:57:28 +020010969 /* Capture mixer control */
10970 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10971 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10972 {
10973 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10974 .name = "Capture Source",
10975 .count = 1,
10976 .info = alc_mux_enum_info,
10977 .get = alc_mux_enum_get,
10978 .put = alc_mux_enum_put,
10979 },
10980 {
10981 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10982 .name = "Channel Mode",
10983 .info = alc_ch_mode_info,
10984 .get = alc_ch_mode_get,
10985 .put = alc_ch_mode_put,
10986 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
10987 },
10988 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010989};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010990
10991static struct snd_kcontrol_new alc861_asus_mixer[] = {
10992 /* output mixer control */
10993 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10994 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10995 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10996 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10997 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10998
10999 /* Input mixer control */
11000 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11001 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11002 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11003 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11004 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11005 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11006 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11007 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11008 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011009 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
11010
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011011 /* Capture mixer control */
11012 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11013 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11014 {
11015 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11016 .name = "Capture Source",
11017 .count = 1,
11018 .info = alc_mux_enum_info,
11019 .get = alc_mux_enum_get,
11020 .put = alc_mux_enum_put,
11021 },
11022 {
11023 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11024 .name = "Channel Mode",
11025 .info = alc_ch_mode_info,
11026 .get = alc_ch_mode_get,
11027 .put = alc_ch_mode_put,
11028 .private_value = ARRAY_SIZE(alc861_asus_modes),
11029 },
11030 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011031};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011032
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011033/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010011034static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011035 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11036 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11037 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
11038 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
11039 { }
11040};
11041
Kailang Yangdf694da2005-12-05 19:42:22 +010011042/*
11043 * generic initialization of ADC, input mixers and output mixers
11044 */
11045static struct hda_verb alc861_base_init_verbs[] = {
11046 /*
11047 * Unmute ADC0 and set the default input to mic-in
11048 */
11049 /* port-A for surround (rear panel) */
11050 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11051 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
11052 /* port-B for mic-in (rear panel) with vref */
11053 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11054 /* port-C for line-in (rear panel) */
11055 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11056 /* port-D for Front */
11057 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11058 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11059 /* port-E for HP out (front panel) */
11060 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11061 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011062 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011063 /* port-F for mic-in (front panel) with vref */
11064 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11065 /* port-G for CLFE (rear panel) */
11066 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11067 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
11068 /* port-H for side (rear panel) */
11069 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11070 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
11071 /* CD-in */
11072 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11073 /* route front mic to ADC1*/
11074 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11075 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11076
11077 /* Unmute DAC0~3 & spdif out*/
11078 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11079 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11080 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11081 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11082 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11083
11084 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11085 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11086 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11087 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11088 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11089
11090 /* Unmute Stereo Mixer 15 */
11091 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11092 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11093 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011094 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011095
11096 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11097 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11098 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11099 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11100 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11101 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11102 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11103 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011104 /* hp used DAC 3 (Front) */
11105 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011106 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11107
11108 { }
11109};
11110
11111static struct hda_verb alc861_threestack_init_verbs[] = {
11112 /*
11113 * Unmute ADC0 and set the default input to mic-in
11114 */
11115 /* port-A for surround (rear panel) */
11116 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11117 /* port-B for mic-in (rear panel) with vref */
11118 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11119 /* port-C for line-in (rear panel) */
11120 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11121 /* port-D for Front */
11122 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11123 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11124 /* port-E for HP out (front panel) */
11125 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11126 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011127 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011128 /* port-F for mic-in (front panel) with vref */
11129 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11130 /* port-G for CLFE (rear panel) */
11131 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11132 /* port-H for side (rear panel) */
11133 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11134 /* CD-in */
11135 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11136 /* route front mic to ADC1*/
11137 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11138 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11139 /* Unmute DAC0~3 & spdif out*/
11140 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11141 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11142 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11143 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11144 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11145
11146 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11147 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11148 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11149 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11150 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11151
11152 /* Unmute Stereo Mixer 15 */
11153 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11154 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11155 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011156 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011157
11158 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11159 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11160 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11161 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11162 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11163 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11164 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11165 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011166 /* hp used DAC 3 (Front) */
11167 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011168 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11169 { }
11170};
Takashi Iwai22309c32006-08-09 16:57:28 +020011171
11172static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
11173 /*
11174 * Unmute ADC0 and set the default input to mic-in
11175 */
11176 /* port-A for surround (rear panel) */
11177 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11178 /* port-B for mic-in (rear panel) with vref */
11179 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11180 /* port-C for line-in (rear panel) */
11181 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11182 /* port-D for Front */
11183 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11184 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11185 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011186 /* this has to be set to VREF80 */
11187 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011188 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011189 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011190 /* port-F for mic-in (front panel) with vref */
11191 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11192 /* port-G for CLFE (rear panel) */
11193 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11194 /* port-H for side (rear panel) */
11195 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11196 /* CD-in */
11197 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11198 /* route front mic to ADC1*/
11199 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11200 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11201 /* Unmute DAC0~3 & spdif out*/
11202 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11203 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11204 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11205 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11206 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11207
11208 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11209 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11210 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11211 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11212 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11213
11214 /* Unmute Stereo Mixer 15 */
11215 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11216 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11217 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011218 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020011219
11220 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11221 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11222 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11223 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11224 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11225 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11226 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11227 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011228 /* hp used DAC 3 (Front) */
11229 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020011230 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11231 { }
11232};
11233
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011234static struct hda_verb alc861_asus_init_verbs[] = {
11235 /*
11236 * Unmute ADC0 and set the default input to mic-in
11237 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011238 /* port-A for surround (rear panel)
11239 * according to codec#0 this is the HP jack
11240 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011241 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
11242 /* route front PCM to HP */
11243 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
11244 /* port-B for mic-in (rear panel) with vref */
11245 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11246 /* port-C for line-in (rear panel) */
11247 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11248 /* port-D for Front */
11249 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11250 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11251 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011252 /* this has to be set to VREF80 */
11253 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011254 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011255 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011256 /* port-F for mic-in (front panel) with vref */
11257 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11258 /* port-G for CLFE (rear panel) */
11259 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11260 /* port-H for side (rear panel) */
11261 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11262 /* CD-in */
11263 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11264 /* route front mic to ADC1*/
11265 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11266 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11267 /* Unmute DAC0~3 & spdif out*/
11268 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11269 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11270 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11271 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11273 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11274 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11275 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11276 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11277 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11278
11279 /* Unmute Stereo Mixer 15 */
11280 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11281 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11282 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011283 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011284
11285 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11286 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11287 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11288 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11289 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11290 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11291 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11292 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011293 /* hp used DAC 3 (Front) */
11294 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011295 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11296 { }
11297};
11298
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011299/* additional init verbs for ASUS laptops */
11300static struct hda_verb alc861_asus_laptop_init_verbs[] = {
11301 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
11302 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
11303 { }
11304};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011305
Kailang Yangdf694da2005-12-05 19:42:22 +010011306/*
11307 * generic initialization of ADC, input mixers and output mixers
11308 */
11309static struct hda_verb alc861_auto_init_verbs[] = {
11310 /*
11311 * Unmute ADC0 and set the default input to mic-in
11312 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011313 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010011314 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11315
11316 /* Unmute DAC0~3 & spdif out*/
11317 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11318 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11319 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11320 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11321 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11322
11323 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11324 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11325 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11326 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11327 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11328
11329 /* Unmute Stereo Mixer 15 */
11330 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11331 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11332 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11333 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
11334
11335 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11336 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11337 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11338 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11339 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11340 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11341 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11342 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11343
11344 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11345 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011346 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11347 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011348 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11349 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011350 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11351 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011352
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011353 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011354
11355 { }
11356};
11357
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011358static struct hda_verb alc861_toshiba_init_verbs[] = {
11359 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011360
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011361 { }
11362};
11363
11364/* toggle speaker-output according to the hp-jack state */
11365static void alc861_toshiba_automute(struct hda_codec *codec)
11366{
11367 unsigned int present;
11368
11369 present = snd_hda_codec_read(codec, 0x0f, 0,
11370 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011371 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
11372 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
11373 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
11374 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011375}
11376
11377static void alc861_toshiba_unsol_event(struct hda_codec *codec,
11378 unsigned int res)
11379{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011380 if ((res >> 26) == ALC880_HP_EVENT)
11381 alc861_toshiba_automute(codec);
11382}
11383
Kailang Yangdf694da2005-12-05 19:42:22 +010011384/* pcm configuration: identiacal with ALC880 */
11385#define alc861_pcm_analog_playback alc880_pcm_analog_playback
11386#define alc861_pcm_analog_capture alc880_pcm_analog_capture
11387#define alc861_pcm_digital_playback alc880_pcm_digital_playback
11388#define alc861_pcm_digital_capture alc880_pcm_digital_capture
11389
11390
11391#define ALC861_DIGOUT_NID 0x07
11392
11393static struct hda_channel_mode alc861_8ch_modes[1] = {
11394 { 8, NULL }
11395};
11396
11397static hda_nid_t alc861_dac_nids[4] = {
11398 /* front, surround, clfe, side */
11399 0x03, 0x06, 0x05, 0x04
11400};
11401
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011402static hda_nid_t alc660_dac_nids[3] = {
11403 /* front, clfe, surround */
11404 0x03, 0x05, 0x06
11405};
11406
Kailang Yangdf694da2005-12-05 19:42:22 +010011407static hda_nid_t alc861_adc_nids[1] = {
11408 /* ADC0-2 */
11409 0x08,
11410};
11411
11412static struct hda_input_mux alc861_capture_source = {
11413 .num_items = 5,
11414 .items = {
11415 { "Mic", 0x0 },
11416 { "Front Mic", 0x3 },
11417 { "Line", 0x1 },
11418 { "CD", 0x4 },
11419 { "Mixer", 0x5 },
11420 },
11421};
11422
11423/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011424static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
11425 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011426{
11427 int i;
11428 hda_nid_t nid;
11429
11430 spec->multiout.dac_nids = spec->private_dac_nids;
11431 for (i = 0; i < cfg->line_outs; i++) {
11432 nid = cfg->line_out_pins[i];
11433 if (nid) {
11434 if (i >= ARRAY_SIZE(alc861_dac_nids))
11435 continue;
11436 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
11437 }
11438 }
11439 spec->multiout.num_dacs = cfg->line_outs;
11440 return 0;
11441}
11442
11443/* add playback controls from the parsed DAC table */
11444static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
11445 const struct auto_pin_cfg *cfg)
11446{
11447 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011448 static const char *chname[4] = {
11449 "Front", "Surround", NULL /*CLFE*/, "Side"
11450 };
Kailang Yangdf694da2005-12-05 19:42:22 +010011451 hda_nid_t nid;
11452 int i, idx, err;
11453
11454 for (i = 0; i < cfg->line_outs; i++) {
11455 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011456 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010011457 continue;
11458 if (nid == 0x05) {
11459 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011460 err = add_control(spec, ALC_CTL_BIND_MUTE,
11461 "Center Playback Switch",
11462 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
11463 HDA_OUTPUT));
11464 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011465 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011466 err = add_control(spec, ALC_CTL_BIND_MUTE,
11467 "LFE Playback Switch",
11468 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11469 HDA_OUTPUT));
11470 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011471 return err;
11472 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011473 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
11474 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010011475 if (nid == alc861_dac_nids[idx])
11476 break;
11477 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011478 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
11479 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11480 HDA_OUTPUT));
11481 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011482 return err;
11483 }
11484 }
11485 return 0;
11486}
11487
11488static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
11489{
11490 int err;
11491 hda_nid_t nid;
11492
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011493 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010011494 return 0;
11495
11496 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
11497 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011498 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11499 "Headphone Playback Switch",
11500 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11501 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011502 return err;
11503 spec->multiout.hp_nid = nid;
11504 }
11505 return 0;
11506}
11507
11508/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011509static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
11510 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011511{
Kailang Yangdf694da2005-12-05 19:42:22 +010011512 struct hda_input_mux *imux = &spec->private_imux;
11513 int i, err, idx, idx1;
11514
11515 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011516 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011517 case 0x0c:
11518 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011519 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011520 break;
11521 case 0x0f:
11522 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011523 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011524 break;
11525 case 0x0d:
11526 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011527 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011528 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011529 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010011530 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011531 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011532 break;
11533 case 0x11:
11534 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011535 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010011536 break;
11537 default:
11538 continue;
11539 }
11540
Takashi Iwai4a471b72005-12-07 13:56:29 +010011541 err = new_analog_input(spec, cfg->input_pins[i],
11542 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010011543 if (err < 0)
11544 return err;
11545
Takashi Iwai4a471b72005-12-07 13:56:29 +010011546 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010011547 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011548 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010011549 }
11550 return 0;
11551}
11552
11553static struct snd_kcontrol_new alc861_capture_mixer[] = {
11554 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11555 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11556
11557 {
11558 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11559 /* The multiple "Capture Source" controls confuse alsamixer
11560 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010011561 */
11562 /* .name = "Capture Source", */
11563 .name = "Input Source",
11564 .count = 1,
11565 .info = alc_mux_enum_info,
11566 .get = alc_mux_enum_get,
11567 .put = alc_mux_enum_put,
11568 },
11569 { } /* end */
11570};
11571
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011572static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
11573 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010011574 int pin_type, int dac_idx)
11575{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011576 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011577}
11578
11579static void alc861_auto_init_multi_out(struct hda_codec *codec)
11580{
11581 struct alc_spec *spec = codec->spec;
11582 int i;
11583
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011584 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010011585 for (i = 0; i < spec->autocfg.line_outs; i++) {
11586 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011587 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011588 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011589 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011590 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011591 }
11592}
11593
11594static void alc861_auto_init_hp_out(struct hda_codec *codec)
11595{
11596 struct alc_spec *spec = codec->spec;
11597 hda_nid_t pin;
11598
Takashi Iwaieb06ed82006-09-20 17:10:27 +020011599 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011600 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011601 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
11602 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011603 pin = spec->autocfg.speaker_pins[0];
11604 if (pin)
11605 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010011606}
11607
11608static void alc861_auto_init_analog_input(struct hda_codec *codec)
11609{
11610 struct alc_spec *spec = codec->spec;
11611 int i;
11612
11613 for (i = 0; i < AUTO_PIN_LAST; i++) {
11614 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011615 if (nid >= 0x0c && nid <= 0x11) {
11616 snd_hda_codec_write(codec, nid, 0,
11617 AC_VERB_SET_PIN_WIDGET_CONTROL,
11618 i <= AUTO_PIN_FRONT_MIC ?
11619 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010011620 }
11621 }
11622}
11623
11624/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011625/* return 1 if successful, 0 if the proper config is not found,
11626 * or a negative error code
11627 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011628static int alc861_parse_auto_config(struct hda_codec *codec)
11629{
11630 struct alc_spec *spec = codec->spec;
11631 int err;
11632 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
11633
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011634 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11635 alc861_ignore);
11636 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011637 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011638 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010011639 return 0; /* can't find valid BIOS pin config */
11640
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011641 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
11642 if (err < 0)
11643 return err;
11644 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
11645 if (err < 0)
11646 return err;
11647 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
11648 if (err < 0)
11649 return err;
11650 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
11651 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011652 return err;
11653
11654 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11655
11656 if (spec->autocfg.dig_out_pin)
11657 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
11658
11659 if (spec->kctl_alloc)
11660 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11661
11662 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
11663
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011664 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010011665 spec->input_mux = &spec->private_imux;
11666
11667 spec->adc_nids = alc861_adc_nids;
11668 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
11669 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
11670 spec->num_mixers++;
11671
11672 return 1;
11673}
11674
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011675/* additional initialization for auto-configuration model */
11676static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011677{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011678 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011679 alc861_auto_init_multi_out(codec);
11680 alc861_auto_init_hp_out(codec);
11681 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011682 if (spec->unsol_event)
11683 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011684}
11685
Takashi Iwaicb53c622007-08-10 17:21:45 +020011686#ifdef CONFIG_SND_HDA_POWER_SAVE
11687static struct hda_amp_list alc861_loopbacks[] = {
11688 { 0x15, HDA_INPUT, 0 },
11689 { 0x15, HDA_INPUT, 1 },
11690 { 0x15, HDA_INPUT, 2 },
11691 { 0x15, HDA_INPUT, 3 },
11692 { } /* end */
11693};
11694#endif
11695
Kailang Yangdf694da2005-12-05 19:42:22 +010011696
11697/*
11698 * configuration and preset
11699 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011700static const char *alc861_models[ALC861_MODEL_LAST] = {
11701 [ALC861_3ST] = "3stack",
11702 [ALC660_3ST] = "3stack-660",
11703 [ALC861_3ST_DIG] = "3stack-dig",
11704 [ALC861_6ST_DIG] = "6stack-dig",
11705 [ALC861_UNIWILL_M31] = "uniwill-m31",
11706 [ALC861_TOSHIBA] = "toshiba",
11707 [ALC861_ASUS] = "asus",
11708 [ALC861_ASUS_LAPTOP] = "asus-laptop",
11709 [ALC861_AUTO] = "auto",
11710};
11711
11712static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010011713 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011714 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11715 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11716 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011717 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020011718 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010011719 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020011720 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
11721 * Any other models that need this preset?
11722 */
11723 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020011724 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
11725 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011726 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
11727 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
11728 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
11729 /* FIXME: the below seems conflict */
11730 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
11731 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
11732 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010011733 {}
11734};
11735
11736static struct alc_config_preset alc861_presets[] = {
11737 [ALC861_3ST] = {
11738 .mixers = { alc861_3ST_mixer },
11739 .init_verbs = { alc861_threestack_init_verbs },
11740 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11741 .dac_nids = alc861_dac_nids,
11742 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11743 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011744 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011745 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11746 .adc_nids = alc861_adc_nids,
11747 .input_mux = &alc861_capture_source,
11748 },
11749 [ALC861_3ST_DIG] = {
11750 .mixers = { alc861_base_mixer },
11751 .init_verbs = { alc861_threestack_init_verbs },
11752 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11753 .dac_nids = alc861_dac_nids,
11754 .dig_out_nid = ALC861_DIGOUT_NID,
11755 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11756 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011757 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011758 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11759 .adc_nids = alc861_adc_nids,
11760 .input_mux = &alc861_capture_source,
11761 },
11762 [ALC861_6ST_DIG] = {
11763 .mixers = { alc861_base_mixer },
11764 .init_verbs = { alc861_base_init_verbs },
11765 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11766 .dac_nids = alc861_dac_nids,
11767 .dig_out_nid = ALC861_DIGOUT_NID,
11768 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
11769 .channel_mode = alc861_8ch_modes,
11770 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11771 .adc_nids = alc861_adc_nids,
11772 .input_mux = &alc861_capture_source,
11773 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011774 [ALC660_3ST] = {
11775 .mixers = { alc861_3ST_mixer },
11776 .init_verbs = { alc861_threestack_init_verbs },
11777 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
11778 .dac_nids = alc660_dac_nids,
11779 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11780 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011781 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011782 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11783 .adc_nids = alc861_adc_nids,
11784 .input_mux = &alc861_capture_source,
11785 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011786 [ALC861_UNIWILL_M31] = {
11787 .mixers = { alc861_uniwill_m31_mixer },
11788 .init_verbs = { alc861_uniwill_m31_init_verbs },
11789 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11790 .dac_nids = alc861_dac_nids,
11791 .dig_out_nid = ALC861_DIGOUT_NID,
11792 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
11793 .channel_mode = alc861_uniwill_m31_modes,
11794 .need_dac_fix = 1,
11795 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11796 .adc_nids = alc861_adc_nids,
11797 .input_mux = &alc861_capture_source,
11798 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011799 [ALC861_TOSHIBA] = {
11800 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011801 .init_verbs = { alc861_base_init_verbs,
11802 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011803 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11804 .dac_nids = alc861_dac_nids,
11805 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11806 .channel_mode = alc883_3ST_2ch_modes,
11807 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11808 .adc_nids = alc861_adc_nids,
11809 .input_mux = &alc861_capture_source,
11810 .unsol_event = alc861_toshiba_unsol_event,
11811 .init_hook = alc861_toshiba_automute,
11812 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011813 [ALC861_ASUS] = {
11814 .mixers = { alc861_asus_mixer },
11815 .init_verbs = { alc861_asus_init_verbs },
11816 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11817 .dac_nids = alc861_dac_nids,
11818 .dig_out_nid = ALC861_DIGOUT_NID,
11819 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
11820 .channel_mode = alc861_asus_modes,
11821 .need_dac_fix = 1,
11822 .hp_nid = 0x06,
11823 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11824 .adc_nids = alc861_adc_nids,
11825 .input_mux = &alc861_capture_source,
11826 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011827 [ALC861_ASUS_LAPTOP] = {
11828 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
11829 .init_verbs = { alc861_asus_init_verbs,
11830 alc861_asus_laptop_init_verbs },
11831 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11832 .dac_nids = alc861_dac_nids,
11833 .dig_out_nid = ALC861_DIGOUT_NID,
11834 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11835 .channel_mode = alc883_3ST_2ch_modes,
11836 .need_dac_fix = 1,
11837 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11838 .adc_nids = alc861_adc_nids,
11839 .input_mux = &alc861_capture_source,
11840 },
11841};
Kailang Yangdf694da2005-12-05 19:42:22 +010011842
11843
11844static int patch_alc861(struct hda_codec *codec)
11845{
11846 struct alc_spec *spec;
11847 int board_config;
11848 int err;
11849
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011850 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011851 if (spec == NULL)
11852 return -ENOMEM;
11853
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011854 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011855
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011856 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
11857 alc861_models,
11858 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011859
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011860 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011861 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
11862 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011863 board_config = ALC861_AUTO;
11864 }
11865
11866 if (board_config == ALC861_AUTO) {
11867 /* automatic parse from the BIOS config */
11868 err = alc861_parse_auto_config(codec);
11869 if (err < 0) {
11870 alc_free(codec);
11871 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011872 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011873 printk(KERN_INFO
11874 "hda_codec: Cannot set up configuration "
11875 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011876 board_config = ALC861_3ST_DIG;
11877 }
11878 }
11879
11880 if (board_config != ALC861_AUTO)
11881 setup_preset(spec, &alc861_presets[board_config]);
11882
11883 spec->stream_name_analog = "ALC861 Analog";
11884 spec->stream_analog_playback = &alc861_pcm_analog_playback;
11885 spec->stream_analog_capture = &alc861_pcm_analog_capture;
11886
11887 spec->stream_name_digital = "ALC861 Digital";
11888 spec->stream_digital_playback = &alc861_pcm_digital_playback;
11889 spec->stream_digital_capture = &alc861_pcm_digital_capture;
11890
Takashi Iwai2134ea42008-01-10 16:53:55 +010011891 spec->vmaster_nid = 0x03;
11892
Kailang Yangdf694da2005-12-05 19:42:22 +010011893 codec->patch_ops = alc_patch_ops;
11894 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011895 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011896#ifdef CONFIG_SND_HDA_POWER_SAVE
11897 if (!spec->loopback.amplist)
11898 spec->loopback.amplist = alc861_loopbacks;
11899#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011900
11901 return 0;
11902}
11903
11904/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011905 * ALC861-VD support
11906 *
11907 * Based on ALC882
11908 *
11909 * In addition, an independent DAC
11910 */
11911#define ALC861VD_DIGOUT_NID 0x06
11912
11913static hda_nid_t alc861vd_dac_nids[4] = {
11914 /* front, surr, clfe, side surr */
11915 0x02, 0x03, 0x04, 0x05
11916};
11917
11918/* dac_nids for ALC660vd are in a different order - according to
11919 * Realtek's driver.
11920 * This should probably tesult in a different mixer for 6stack models
11921 * of ALC660vd codecs, but for now there is only 3stack mixer
11922 * - and it is the same as in 861vd.
11923 * adc_nids in ALC660vd are (is) the same as in 861vd
11924 */
11925static hda_nid_t alc660vd_dac_nids[3] = {
11926 /* front, rear, clfe, rear_surr */
11927 0x02, 0x04, 0x03
11928};
11929
11930static hda_nid_t alc861vd_adc_nids[1] = {
11931 /* ADC0 */
11932 0x09,
11933};
11934
Takashi Iwaie1406342008-02-11 18:32:32 +010011935static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
11936
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011937/* input MUX */
11938/* FIXME: should be a matrix-type input source selection */
11939static struct hda_input_mux alc861vd_capture_source = {
11940 .num_items = 4,
11941 .items = {
11942 { "Mic", 0x0 },
11943 { "Front Mic", 0x1 },
11944 { "Line", 0x2 },
11945 { "CD", 0x4 },
11946 },
11947};
11948
Kailang Yang272a5272007-05-14 11:00:38 +020011949static struct hda_input_mux alc861vd_dallas_capture_source = {
11950 .num_items = 3,
11951 .items = {
11952 { "Front Mic", 0x0 },
11953 { "ATAPI Mic", 0x1 },
11954 { "Line In", 0x5 },
11955 },
11956};
11957
Kailang Yangd1a991a2007-08-15 16:21:59 +020011958static struct hda_input_mux alc861vd_hp_capture_source = {
11959 .num_items = 2,
11960 .items = {
11961 { "Front Mic", 0x0 },
11962 { "ATAPI Mic", 0x1 },
11963 },
11964};
11965
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011966#define alc861vd_mux_enum_info alc_mux_enum_info
11967#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010011968/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
11969#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011970
11971/*
11972 * 2ch mode
11973 */
11974static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
11975 { 2, NULL }
11976};
11977
11978/*
11979 * 6ch mode
11980 */
11981static struct hda_verb alc861vd_6stack_ch6_init[] = {
11982 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11983 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11984 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11985 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11986 { } /* end */
11987};
11988
11989/*
11990 * 8ch mode
11991 */
11992static struct hda_verb alc861vd_6stack_ch8_init[] = {
11993 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11994 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11995 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11996 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11997 { } /* end */
11998};
11999
12000static struct hda_channel_mode alc861vd_6stack_modes[2] = {
12001 { 6, alc861vd_6stack_ch6_init },
12002 { 8, alc861vd_6stack_ch8_init },
12003};
12004
12005static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
12006 {
12007 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12008 .name = "Channel Mode",
12009 .info = alc_ch_mode_info,
12010 .get = alc_ch_mode_get,
12011 .put = alc_ch_mode_put,
12012 },
12013 { } /* end */
12014};
12015
12016static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
12017 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
12018 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
12019
12020 {
12021 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12022 /* The multiple "Capture Source" controls confuse alsamixer
12023 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012024 */
12025 /* .name = "Capture Source", */
12026 .name = "Input Source",
12027 .count = 1,
12028 .info = alc861vd_mux_enum_info,
12029 .get = alc861vd_mux_enum_get,
12030 .put = alc861vd_mux_enum_put,
12031 },
12032 { } /* end */
12033};
12034
12035/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12036 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12037 */
12038static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
12039 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12040 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12041
12042 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12043 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
12044
12045 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
12046 HDA_OUTPUT),
12047 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
12048 HDA_OUTPUT),
12049 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
12050 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
12051
12052 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
12053 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
12054
12055 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12056
12057 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12058 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12059 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12060
12061 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12062 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12063 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12064
12065 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12066 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12067
12068 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12069 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12070
12071 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12072 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
12073
12074 { } /* end */
12075};
12076
12077static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
12078 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12079 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12080
12081 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12082
12083 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12084 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12085 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12086
12087 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12088 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12089 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12090
12091 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12092 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12093
12094 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12095 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12096
12097 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12098 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
12099
12100 { } /* end */
12101};
12102
Kailang Yangbdd148a2007-05-08 15:19:08 +020012103static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
12104 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12105 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
12106 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12107
12108 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12109
12110 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12111 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12112 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12113
12114 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12115 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12116 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12117
12118 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12119 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12120
12121 { } /* end */
12122};
12123
Kailang Yang272a5272007-05-14 11:00:38 +020012124/* Pin assignment: Front=0x14, HP = 0x15,
12125 * Front Mic=0x18, ATAPI Mic = 0x19, Line In = 0x1d
12126 */
12127static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
12128 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12129 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12130 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12131 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12132 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12133 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12134 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12135 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12136 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT),
12137 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012138 { } /* end */
12139};
12140
Kailang Yangd1a991a2007-08-15 16:21:59 +020012141/* Pin assignment: Speaker=0x14, Line-out = 0x15,
12142 * Front Mic=0x18, ATAPI Mic = 0x19,
12143 */
12144static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
12145 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12146 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12147 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12148 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12149 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12150 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12151 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12152 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12153
12154 { } /* end */
12155};
12156
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012157/*
12158 * generic initialization of ADC, input mixers and output mixers
12159 */
12160static struct hda_verb alc861vd_volume_init_verbs[] = {
12161 /*
12162 * Unmute ADC0 and set the default input to mic-in
12163 */
12164 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12165 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12166
12167 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
12168 * the analog-loopback mixer widget
12169 */
12170 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012171 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12172 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12173 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12174 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12175 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012176
12177 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020012178 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12179 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12180 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012181 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012182
12183 /*
12184 * Set up output mixers (0x02 - 0x05)
12185 */
12186 /* set vol=0 to output mixers */
12187 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12188 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12189 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12190 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12191
12192 /* set up input amps for analog loopback */
12193 /* Amp Indices: DAC = 0, mixer = 1 */
12194 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12195 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12196 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12197 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12198 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12199 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12200 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12201 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12202
12203 { }
12204};
12205
12206/*
12207 * 3-stack pin configuration:
12208 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
12209 */
12210static struct hda_verb alc861vd_3stack_init_verbs[] = {
12211 /*
12212 * Set pin mode and muting
12213 */
12214 /* set front pin widgets 0x14 for output */
12215 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12216 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12217 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12218
12219 /* Mic (rear) pin: input vref at 80% */
12220 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12221 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12222 /* Front Mic pin: input vref at 80% */
12223 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12224 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12225 /* Line In pin: input */
12226 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12227 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12228 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12229 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12230 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12231 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12232 /* CD pin widget for input */
12233 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12234
12235 { }
12236};
12237
12238/*
12239 * 6-stack pin configuration:
12240 */
12241static struct hda_verb alc861vd_6stack_init_verbs[] = {
12242 /*
12243 * Set pin mode and muting
12244 */
12245 /* set front pin widgets 0x14 for output */
12246 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12247 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12248 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12249
12250 /* Rear Pin: output 1 (0x0d) */
12251 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12252 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12253 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12254 /* CLFE Pin: output 2 (0x0e) */
12255 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12256 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12257 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
12258 /* Side Pin: output 3 (0x0f) */
12259 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12260 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12261 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
12262
12263 /* Mic (rear) pin: input vref at 80% */
12264 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12265 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12266 /* Front Mic pin: input vref at 80% */
12267 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12268 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12269 /* Line In pin: input */
12270 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12271 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12272 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12273 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12274 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12275 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12276 /* CD pin widget for input */
12277 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12278
12279 { }
12280};
12281
Kailang Yangbdd148a2007-05-08 15:19:08 +020012282static struct hda_verb alc861vd_eapd_verbs[] = {
12283 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12284 { }
12285};
12286
12287static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
12288 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12289 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12290 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12291 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12292 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12293 {}
12294};
12295
12296/* toggle speaker-output according to the hp-jack state */
12297static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
12298{
12299 unsigned int present;
12300 unsigned char bits;
12301
12302 present = snd_hda_codec_read(codec, 0x1b, 0,
12303 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012304 bits = present ? HDA_AMP_MUTE : 0;
12305 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12306 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012307}
12308
12309static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
12310{
12311 unsigned int present;
12312 unsigned char bits;
12313
12314 present = snd_hda_codec_read(codec, 0x18, 0,
12315 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012316 bits = present ? HDA_AMP_MUTE : 0;
12317 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
12318 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012319}
12320
12321static void alc861vd_lenovo_automute(struct hda_codec *codec)
12322{
12323 alc861vd_lenovo_hp_automute(codec);
12324 alc861vd_lenovo_mic_automute(codec);
12325}
12326
12327static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
12328 unsigned int res)
12329{
12330 switch (res >> 26) {
12331 case ALC880_HP_EVENT:
12332 alc861vd_lenovo_hp_automute(codec);
12333 break;
12334 case ALC880_MIC_EVENT:
12335 alc861vd_lenovo_mic_automute(codec);
12336 break;
12337 }
12338}
12339
Kailang Yang272a5272007-05-14 11:00:38 +020012340static struct hda_verb alc861vd_dallas_verbs[] = {
12341 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12342 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12343 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12344 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12345
12346 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12347 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12348 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12349 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12350 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12351 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12352 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12353 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12354
12355 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12356 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12357 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12358 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12359 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12360 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12361 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12362 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12363
12364 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12365 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12366 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12367 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12368 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12369 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12370 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12371 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12372
12373 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12374 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12375 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12376 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12377
12378 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12379 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12380 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12381
12382 { } /* end */
12383};
12384
12385/* toggle speaker-output according to the hp-jack state */
12386static void alc861vd_dallas_automute(struct hda_codec *codec)
12387{
12388 unsigned int present;
12389
12390 present = snd_hda_codec_read(codec, 0x15, 0,
12391 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012392 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12393 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020012394}
12395
12396static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
12397{
12398 if ((res >> 26) == ALC880_HP_EVENT)
12399 alc861vd_dallas_automute(codec);
12400}
12401
Takashi Iwaicb53c622007-08-10 17:21:45 +020012402#ifdef CONFIG_SND_HDA_POWER_SAVE
12403#define alc861vd_loopbacks alc880_loopbacks
12404#endif
12405
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012406/* pcm configuration: identiacal with ALC880 */
12407#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
12408#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
12409#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
12410#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
12411
12412/*
12413 * configuration and preset
12414 */
12415static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
12416 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012417 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012418 [ALC861VD_3ST] = "3stack",
12419 [ALC861VD_3ST_DIG] = "3stack-digout",
12420 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020012421 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020012422 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012423 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012424 [ALC861VD_AUTO] = "auto",
12425};
12426
12427static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012428 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
12429 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010012430 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012431 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020012432 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012433 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012434 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020012435 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020012436 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020012437 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Takashi Iwai39c5d412007-08-15 16:24:17 +020012438 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012439 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
12440 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020012441 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012442 {}
12443};
12444
12445static struct alc_config_preset alc861vd_presets[] = {
12446 [ALC660VD_3ST] = {
12447 .mixers = { alc861vd_3st_mixer },
12448 .init_verbs = { alc861vd_volume_init_verbs,
12449 alc861vd_3stack_init_verbs },
12450 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12451 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012452 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12453 .channel_mode = alc861vd_3stack_2ch_modes,
12454 .input_mux = &alc861vd_capture_source,
12455 },
Mike Crash6963f842007-06-25 12:12:51 +020012456 [ALC660VD_3ST_DIG] = {
12457 .mixers = { alc861vd_3st_mixer },
12458 .init_verbs = { alc861vd_volume_init_verbs,
12459 alc861vd_3stack_init_verbs },
12460 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12461 .dac_nids = alc660vd_dac_nids,
12462 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020012463 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12464 .channel_mode = alc861vd_3stack_2ch_modes,
12465 .input_mux = &alc861vd_capture_source,
12466 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012467 [ALC861VD_3ST] = {
12468 .mixers = { alc861vd_3st_mixer },
12469 .init_verbs = { alc861vd_volume_init_verbs,
12470 alc861vd_3stack_init_verbs },
12471 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12472 .dac_nids = alc861vd_dac_nids,
12473 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12474 .channel_mode = alc861vd_3stack_2ch_modes,
12475 .input_mux = &alc861vd_capture_source,
12476 },
12477 [ALC861VD_3ST_DIG] = {
12478 .mixers = { alc861vd_3st_mixer },
12479 .init_verbs = { alc861vd_volume_init_verbs,
12480 alc861vd_3stack_init_verbs },
12481 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12482 .dac_nids = alc861vd_dac_nids,
12483 .dig_out_nid = ALC861VD_DIGOUT_NID,
12484 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12485 .channel_mode = alc861vd_3stack_2ch_modes,
12486 .input_mux = &alc861vd_capture_source,
12487 },
12488 [ALC861VD_6ST_DIG] = {
12489 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
12490 .init_verbs = { alc861vd_volume_init_verbs,
12491 alc861vd_6stack_init_verbs },
12492 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12493 .dac_nids = alc861vd_dac_nids,
12494 .dig_out_nid = ALC861VD_DIGOUT_NID,
12495 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
12496 .channel_mode = alc861vd_6stack_modes,
12497 .input_mux = &alc861vd_capture_source,
12498 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020012499 [ALC861VD_LENOVO] = {
12500 .mixers = { alc861vd_lenovo_mixer },
12501 .init_verbs = { alc861vd_volume_init_verbs,
12502 alc861vd_3stack_init_verbs,
12503 alc861vd_eapd_verbs,
12504 alc861vd_lenovo_unsol_verbs },
12505 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12506 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012507 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12508 .channel_mode = alc861vd_3stack_2ch_modes,
12509 .input_mux = &alc861vd_capture_source,
12510 .unsol_event = alc861vd_lenovo_unsol_event,
12511 .init_hook = alc861vd_lenovo_automute,
12512 },
Kailang Yang272a5272007-05-14 11:00:38 +020012513 [ALC861VD_DALLAS] = {
12514 .mixers = { alc861vd_dallas_mixer },
12515 .init_verbs = { alc861vd_dallas_verbs },
12516 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12517 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020012518 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12519 .channel_mode = alc861vd_3stack_2ch_modes,
12520 .input_mux = &alc861vd_dallas_capture_source,
12521 .unsol_event = alc861vd_dallas_unsol_event,
12522 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012523 },
12524 [ALC861VD_HP] = {
12525 .mixers = { alc861vd_hp_mixer },
12526 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
12527 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12528 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012529 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012530 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12531 .channel_mode = alc861vd_3stack_2ch_modes,
12532 .input_mux = &alc861vd_hp_capture_source,
12533 .unsol_event = alc861vd_dallas_unsol_event,
12534 .init_hook = alc861vd_dallas_automute,
12535 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012536};
12537
12538/*
12539 * BIOS auto configuration
12540 */
12541static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
12542 hda_nid_t nid, int pin_type, int dac_idx)
12543{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012544 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012545}
12546
12547static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
12548{
12549 struct alc_spec *spec = codec->spec;
12550 int i;
12551
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012552 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012553 for (i = 0; i <= HDA_SIDE; i++) {
12554 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012555 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012556 if (nid)
12557 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012558 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012559 }
12560}
12561
12562
12563static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
12564{
12565 struct alc_spec *spec = codec->spec;
12566 hda_nid_t pin;
12567
12568 pin = spec->autocfg.hp_pins[0];
12569 if (pin) /* connect to front and use dac 0 */
12570 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012571 pin = spec->autocfg.speaker_pins[0];
12572 if (pin)
12573 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012574}
12575
12576#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
12577#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
12578
12579static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
12580{
12581 struct alc_spec *spec = codec->spec;
12582 int i;
12583
12584 for (i = 0; i < AUTO_PIN_LAST; i++) {
12585 hda_nid_t nid = spec->autocfg.input_pins[i];
12586 if (alc861vd_is_input_pin(nid)) {
12587 snd_hda_codec_write(codec, nid, 0,
12588 AC_VERB_SET_PIN_WIDGET_CONTROL,
12589 i <= AUTO_PIN_FRONT_MIC ?
12590 PIN_VREF80 : PIN_IN);
12591 if (nid != ALC861VD_PIN_CD_NID)
12592 snd_hda_codec_write(codec, nid, 0,
12593 AC_VERB_SET_AMP_GAIN_MUTE,
12594 AMP_OUT_MUTE);
12595 }
12596 }
12597}
12598
12599#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
12600#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
12601
12602/* add playback controls from the parsed DAC table */
12603/* Based on ALC880 version. But ALC861VD has separate,
12604 * different NIDs for mute/unmute switch and volume control */
12605static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
12606 const struct auto_pin_cfg *cfg)
12607{
12608 char name[32];
12609 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
12610 hda_nid_t nid_v, nid_s;
12611 int i, err;
12612
12613 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012614 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012615 continue;
12616 nid_v = alc861vd_idx_to_mixer_vol(
12617 alc880_dac_to_idx(
12618 spec->multiout.dac_nids[i]));
12619 nid_s = alc861vd_idx_to_mixer_switch(
12620 alc880_dac_to_idx(
12621 spec->multiout.dac_nids[i]));
12622
12623 if (i == 2) {
12624 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012625 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12626 "Center Playback Volume",
12627 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
12628 HDA_OUTPUT));
12629 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012630 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012631 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12632 "LFE Playback Volume",
12633 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
12634 HDA_OUTPUT));
12635 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012636 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012637 err = add_control(spec, ALC_CTL_BIND_MUTE,
12638 "Center Playback Switch",
12639 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12640 HDA_INPUT));
12641 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012642 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012643 err = add_control(spec, ALC_CTL_BIND_MUTE,
12644 "LFE Playback Switch",
12645 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12646 HDA_INPUT));
12647 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012648 return err;
12649 } else {
12650 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012651 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12652 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
12653 HDA_OUTPUT));
12654 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012655 return err;
12656 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012657 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012658 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012659 HDA_INPUT));
12660 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012661 return err;
12662 }
12663 }
12664 return 0;
12665}
12666
12667/* add playback controls for speaker and HP outputs */
12668/* Based on ALC880 version. But ALC861VD has separate,
12669 * different NIDs for mute/unmute switch and volume control */
12670static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
12671 hda_nid_t pin, const char *pfx)
12672{
12673 hda_nid_t nid_v, nid_s;
12674 int err;
12675 char name[32];
12676
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012677 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012678 return 0;
12679
12680 if (alc880_is_fixed_pin(pin)) {
12681 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12682 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012683 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012684 spec->multiout.hp_nid = nid_v;
12685 else
12686 spec->multiout.extra_out_nid[0] = nid_v;
12687 /* control HP volume/switch on the output mixer amp */
12688 nid_v = alc861vd_idx_to_mixer_vol(
12689 alc880_fixed_pin_idx(pin));
12690 nid_s = alc861vd_idx_to_mixer_switch(
12691 alc880_fixed_pin_idx(pin));
12692
12693 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012694 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12695 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
12696 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012697 return err;
12698 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012699 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12700 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
12701 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012702 return err;
12703 } else if (alc880_is_multi_pin(pin)) {
12704 /* set manual connection */
12705 /* we have only a switch on HP-out PIN */
12706 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012707 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12708 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12709 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012710 return err;
12711 }
12712 return 0;
12713}
12714
12715/* parse the BIOS configuration and set up the alc_spec
12716 * return 1 if successful, 0 if the proper config is not found,
12717 * or a negative error code
12718 * Based on ALC880 version - had to change it to override
12719 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
12720static int alc861vd_parse_auto_config(struct hda_codec *codec)
12721{
12722 struct alc_spec *spec = codec->spec;
12723 int err;
12724 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
12725
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012726 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12727 alc861vd_ignore);
12728 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012729 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012730 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012731 return 0; /* can't find valid BIOS pin config */
12732
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012733 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12734 if (err < 0)
12735 return err;
12736 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
12737 if (err < 0)
12738 return err;
12739 err = alc861vd_auto_create_extra_out(spec,
12740 spec->autocfg.speaker_pins[0],
12741 "Speaker");
12742 if (err < 0)
12743 return err;
12744 err = alc861vd_auto_create_extra_out(spec,
12745 spec->autocfg.hp_pins[0],
12746 "Headphone");
12747 if (err < 0)
12748 return err;
12749 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
12750 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012751 return err;
12752
12753 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12754
12755 if (spec->autocfg.dig_out_pin)
12756 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
12757
12758 if (spec->kctl_alloc)
12759 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12760
12761 spec->init_verbs[spec->num_init_verbs++]
12762 = alc861vd_volume_init_verbs;
12763
12764 spec->num_mux_defs = 1;
12765 spec->input_mux = &spec->private_imux;
12766
Takashi Iwai776e1842007-08-29 15:07:11 +020012767 err = alc_auto_add_mic_boost(codec);
12768 if (err < 0)
12769 return err;
12770
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012771 return 1;
12772}
12773
12774/* additional initialization for auto-configuration model */
12775static void alc861vd_auto_init(struct hda_codec *codec)
12776{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012777 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012778 alc861vd_auto_init_multi_out(codec);
12779 alc861vd_auto_init_hp_out(codec);
12780 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012781 if (spec->unsol_event)
12782 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012783}
12784
12785static int patch_alc861vd(struct hda_codec *codec)
12786{
12787 struct alc_spec *spec;
12788 int err, board_config;
12789
12790 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12791 if (spec == NULL)
12792 return -ENOMEM;
12793
12794 codec->spec = spec;
12795
12796 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
12797 alc861vd_models,
12798 alc861vd_cfg_tbl);
12799
12800 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
12801 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
12802 "ALC861VD, trying auto-probe from BIOS...\n");
12803 board_config = ALC861VD_AUTO;
12804 }
12805
12806 if (board_config == ALC861VD_AUTO) {
12807 /* automatic parse from the BIOS config */
12808 err = alc861vd_parse_auto_config(codec);
12809 if (err < 0) {
12810 alc_free(codec);
12811 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012812 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012813 printk(KERN_INFO
12814 "hda_codec: Cannot set up configuration "
12815 "from BIOS. Using base mode...\n");
12816 board_config = ALC861VD_3ST;
12817 }
12818 }
12819
12820 if (board_config != ALC861VD_AUTO)
12821 setup_preset(spec, &alc861vd_presets[board_config]);
12822
12823 spec->stream_name_analog = "ALC861VD Analog";
12824 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
12825 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
12826
12827 spec->stream_name_digital = "ALC861VD Digital";
12828 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
12829 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
12830
12831 spec->adc_nids = alc861vd_adc_nids;
12832 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010012833 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012834
12835 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
12836 spec->num_mixers++;
12837
Takashi Iwai2134ea42008-01-10 16:53:55 +010012838 spec->vmaster_nid = 0x02;
12839
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012840 codec->patch_ops = alc_patch_ops;
12841
12842 if (board_config == ALC861VD_AUTO)
12843 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012844#ifdef CONFIG_SND_HDA_POWER_SAVE
12845 if (!spec->loopback.amplist)
12846 spec->loopback.amplist = alc861vd_loopbacks;
12847#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012848
12849 return 0;
12850}
12851
12852/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012853 * ALC662 support
12854 *
12855 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
12856 * configuration. Each pin widget can choose any input DACs and a mixer.
12857 * Each ADC is connected from a mixer of all inputs. This makes possible
12858 * 6-channel independent captures.
12859 *
12860 * In addition, an independent DAC for the multi-playback (not used in this
12861 * driver yet).
12862 */
12863#define ALC662_DIGOUT_NID 0x06
12864#define ALC662_DIGIN_NID 0x0a
12865
12866static hda_nid_t alc662_dac_nids[4] = {
12867 /* front, rear, clfe, rear_surr */
12868 0x02, 0x03, 0x04
12869};
12870
12871static hda_nid_t alc662_adc_nids[1] = {
12872 /* ADC1-2 */
12873 0x09,
12874};
Takashi Iwaie1406342008-02-11 18:32:32 +010012875
Kailang Yang77a261b2008-02-19 11:38:05 +010012876static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010012877
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012878/* input MUX */
12879/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012880static struct hda_input_mux alc662_capture_source = {
12881 .num_items = 4,
12882 .items = {
12883 { "Mic", 0x0 },
12884 { "Front Mic", 0x1 },
12885 { "Line", 0x2 },
12886 { "CD", 0x4 },
12887 },
12888};
12889
12890static struct hda_input_mux alc662_lenovo_101e_capture_source = {
12891 .num_items = 2,
12892 .items = {
12893 { "Mic", 0x1 },
12894 { "Line", 0x2 },
12895 },
12896};
Kailang Yang291702f2007-10-16 14:28:03 +020012897
12898static struct hda_input_mux alc662_eeepc_capture_source = {
12899 .num_items = 2,
12900 .items = {
12901 { "i-Mic", 0x1 },
12902 { "e-Mic", 0x0 },
12903 },
12904};
12905
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012906#define alc662_mux_enum_info alc_mux_enum_info
12907#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010012908#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012909
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012910/*
12911 * 2ch mode
12912 */
12913static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
12914 { 2, NULL }
12915};
12916
12917/*
12918 * 2ch mode
12919 */
12920static struct hda_verb alc662_3ST_ch2_init[] = {
12921 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
12922 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12923 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
12924 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12925 { } /* end */
12926};
12927
12928/*
12929 * 6ch mode
12930 */
12931static struct hda_verb alc662_3ST_ch6_init[] = {
12932 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12933 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12934 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
12935 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12936 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12937 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
12938 { } /* end */
12939};
12940
12941static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
12942 { 2, alc662_3ST_ch2_init },
12943 { 6, alc662_3ST_ch6_init },
12944};
12945
12946/*
12947 * 2ch mode
12948 */
12949static struct hda_verb alc662_sixstack_ch6_init[] = {
12950 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12951 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12952 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12953 { } /* end */
12954};
12955
12956/*
12957 * 6ch mode
12958 */
12959static struct hda_verb alc662_sixstack_ch8_init[] = {
12960 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12961 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12962 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12963 { } /* end */
12964};
12965
12966static struct hda_channel_mode alc662_5stack_modes[2] = {
12967 { 2, alc662_sixstack_ch6_init },
12968 { 6, alc662_sixstack_ch8_init },
12969};
12970
12971/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12972 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12973 */
12974
12975static struct snd_kcontrol_new alc662_base_mixer[] = {
12976 /* output mixer control */
12977 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12978 HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
12979 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12980 HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12981 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12982 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12983 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12984 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12985 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12986
12987 /*Input mixer control */
12988 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
12989 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
12990 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
12991 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
12992 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
12993 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
12994 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
12995 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012996 { } /* end */
12997};
12998
12999static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
13000 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13001 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
13002 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13003 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13004 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13005 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13006 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13007 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13008 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13009 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13010 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13011 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13012 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013013 { } /* end */
13014};
13015
13016static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
13017 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13018 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
13019 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13020 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
13021 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13022 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
13023 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
13024 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
13025 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13026 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13027 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13028 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13029 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13030 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13031 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13032 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13033 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13034 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13035 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013036 { } /* end */
13037};
13038
13039static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
13040 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13041 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010013042 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13043 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013044 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13045 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13046 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13047 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13048 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013049 { } /* end */
13050};
13051
Kailang Yang291702f2007-10-16 14:28:03 +020013052static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010013053 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020013054
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010013055 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13056 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020013057
13058 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
13059 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13060 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13061
13062 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
13063 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13064 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13065 { } /* end */
13066};
13067
Kailang Yang8c427222008-01-10 13:03:59 +010013068static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010013069 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13070 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010013071 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13072 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
13073 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13074 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
13075 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
13076 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010013077 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010013078 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
13079 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13080 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13081 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13082 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13083 { } /* end */
13084};
13085
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013086static struct snd_kcontrol_new alc662_chmode_mixer[] = {
13087 {
13088 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13089 .name = "Channel Mode",
13090 .info = alc_ch_mode_info,
13091 .get = alc_ch_mode_get,
13092 .put = alc_ch_mode_put,
13093 },
13094 { } /* end */
13095};
13096
13097static struct hda_verb alc662_init_verbs[] = {
13098 /* ADC: mute amp left and right */
13099 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13100 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13101 /* Front mixer: unmute input/output amp left and right (volume = 0) */
13102
Takashi Iwaicb53c622007-08-10 17:21:45 +020013103 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13104 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13105 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13106 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13107 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013108
Kailang Yangb60dd392007-09-20 12:50:29 +020013109 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13110 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13111 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13112 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13113 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13114 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013115
13116 /* Front Pin: output 0 (0x0c) */
13117 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13118 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13119
13120 /* Rear Pin: output 1 (0x0d) */
13121 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13122 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13123
13124 /* CLFE Pin: output 2 (0x0e) */
13125 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13126 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13127
13128 /* Mic (rear) pin: input vref at 80% */
13129 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13130 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13131 /* Front Mic pin: input vref at 80% */
13132 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13133 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13134 /* Line In pin: input */
13135 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13136 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13137 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13138 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13139 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13140 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13141 /* CD pin widget for input */
13142 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13143
13144 /* FIXME: use matrix-type input source selection */
13145 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13146 /* Input mixer */
13147 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13148 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13149 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13150 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020013151
13152 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13153 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13154 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13155 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013156 { }
13157};
13158
13159static struct hda_verb alc662_sue_init_verbs[] = {
13160 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
13161 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020013162 {}
13163};
13164
13165static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
13166 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13167 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13168 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013169};
13170
Kailang Yang8c427222008-01-10 13:03:59 +010013171/* Set Unsolicited Event*/
13172static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
13173 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13174 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13175 {}
13176};
13177
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013178/*
13179 * generic initialization of ADC, input mixers and output mixers
13180 */
13181static struct hda_verb alc662_auto_init_verbs[] = {
13182 /*
13183 * Unmute ADC and set the default input to mic-in
13184 */
13185 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13186 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13187
13188 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
13189 * mixer widget
13190 * Note: PASD motherboards uses the Line In 2 as the input for front
13191 * panel mic (mic 2)
13192 */
13193 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013194 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13195 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13196 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13197 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13198 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013199
13200 /*
13201 * Set up output mixers (0x0c - 0x0f)
13202 */
13203 /* set vol=0 to output mixers */
13204 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13205 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13206 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13207
13208 /* set up input amps for analog loopback */
13209 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020013210 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13211 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13212 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13213 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13214 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13215 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013216
13217
13218 /* FIXME: use matrix-type input source selection */
13219 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13220 /* Input mixer */
13221 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020013222 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013223 { }
13224};
13225
13226/* capture mixer elements */
13227static struct snd_kcontrol_new alc662_capture_mixer[] = {
13228 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13229 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13230 {
13231 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13232 /* The multiple "Capture Source" controls confuse alsamixer
13233 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013234 */
13235 /* .name = "Capture Source", */
13236 .name = "Input Source",
13237 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010013238 .info = alc662_mux_enum_info,
13239 .get = alc662_mux_enum_get,
13240 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013241 },
13242 { } /* end */
13243};
13244
13245static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
13246{
13247 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013248 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013249
13250 present = snd_hda_codec_read(codec, 0x14, 0,
13251 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013252 bits = present ? HDA_AMP_MUTE : 0;
13253 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13254 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013255}
13256
13257static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
13258{
13259 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013260 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013261
13262 present = snd_hda_codec_read(codec, 0x1b, 0,
13263 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013264 bits = present ? HDA_AMP_MUTE : 0;
13265 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13266 HDA_AMP_MUTE, bits);
13267 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13268 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013269}
13270
13271static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
13272 unsigned int res)
13273{
13274 if ((res >> 26) == ALC880_HP_EVENT)
13275 alc662_lenovo_101e_all_automute(codec);
13276 if ((res >> 26) == ALC880_FRONT_EVENT)
13277 alc662_lenovo_101e_ispeaker_automute(codec);
13278}
13279
Kailang Yang291702f2007-10-16 14:28:03 +020013280static void alc662_eeepc_mic_automute(struct hda_codec *codec)
13281{
13282 unsigned int present;
13283
13284 present = snd_hda_codec_read(codec, 0x18, 0,
13285 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
13286 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13287 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13288 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13289 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13290 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13291 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13292 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13293 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13294}
13295
13296/* unsolicited event for HP jack sensing */
13297static void alc662_eeepc_unsol_event(struct hda_codec *codec,
13298 unsigned int res)
13299{
13300 if ((res >> 26) == ALC880_HP_EVENT)
13301 alc262_hippo1_automute( codec );
13302
13303 if ((res >> 26) == ALC880_MIC_EVENT)
13304 alc662_eeepc_mic_automute(codec);
13305}
13306
13307static void alc662_eeepc_inithook(struct hda_codec *codec)
13308{
13309 alc262_hippo1_automute( codec );
13310 alc662_eeepc_mic_automute(codec);
13311}
13312
Kailang Yang8c427222008-01-10 13:03:59 +010013313static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
13314{
13315 unsigned int mute;
13316 unsigned int present;
13317
13318 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
13319 present = snd_hda_codec_read(codec, 0x14, 0,
13320 AC_VERB_GET_PIN_SENSE, 0);
13321 present = (present & 0x80000000) != 0;
13322 if (present) {
13323 /* mute internal speaker */
13324 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13325 HDA_AMP_MUTE, HDA_AMP_MUTE);
13326 } else {
13327 /* unmute internal speaker if necessary */
13328 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13329 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13330 HDA_AMP_MUTE, mute);
13331 }
13332}
13333
13334/* unsolicited event for HP jack sensing */
13335static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
13336 unsigned int res)
13337{
13338 if ((res >> 26) == ALC880_HP_EVENT)
13339 alc662_eeepc_ep20_automute(codec);
13340}
13341
13342static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
13343{
13344 alc662_eeepc_ep20_automute(codec);
13345}
13346
Takashi Iwaicb53c622007-08-10 17:21:45 +020013347#ifdef CONFIG_SND_HDA_POWER_SAVE
13348#define alc662_loopbacks alc880_loopbacks
13349#endif
13350
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013351
13352/* pcm configuration: identiacal with ALC880 */
13353#define alc662_pcm_analog_playback alc880_pcm_analog_playback
13354#define alc662_pcm_analog_capture alc880_pcm_analog_capture
13355#define alc662_pcm_digital_playback alc880_pcm_digital_playback
13356#define alc662_pcm_digital_capture alc880_pcm_digital_capture
13357
13358/*
13359 * configuration and preset
13360 */
13361static const char *alc662_models[ALC662_MODEL_LAST] = {
13362 [ALC662_3ST_2ch_DIG] = "3stack-dig",
13363 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
13364 [ALC662_3ST_6ch] = "3stack-6ch",
13365 [ALC662_5ST_DIG] = "6stack-dig",
13366 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020013367 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010013368 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013369 [ALC662_AUTO] = "auto",
13370};
13371
13372static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013373 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010013374 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013375 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013376 {}
13377};
13378
13379static struct alc_config_preset alc662_presets[] = {
13380 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013381 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013382 .init_verbs = { alc662_init_verbs },
13383 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13384 .dac_nids = alc662_dac_nids,
13385 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013386 .dig_in_nid = ALC662_DIGIN_NID,
13387 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13388 .channel_mode = alc662_3ST_2ch_modes,
13389 .input_mux = &alc662_capture_source,
13390 },
13391 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013392 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13393 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013394 .init_verbs = { alc662_init_verbs },
13395 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13396 .dac_nids = alc662_dac_nids,
13397 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013398 .dig_in_nid = ALC662_DIGIN_NID,
13399 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13400 .channel_mode = alc662_3ST_6ch_modes,
13401 .need_dac_fix = 1,
13402 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013403 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013404 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013405 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13406 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013407 .init_verbs = { alc662_init_verbs },
13408 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13409 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013410 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13411 .channel_mode = alc662_3ST_6ch_modes,
13412 .need_dac_fix = 1,
13413 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013414 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013415 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013416 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
13417 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013418 .init_verbs = { alc662_init_verbs },
13419 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13420 .dac_nids = alc662_dac_nids,
13421 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013422 .dig_in_nid = ALC662_DIGIN_NID,
13423 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
13424 .channel_mode = alc662_5stack_modes,
13425 .input_mux = &alc662_capture_source,
13426 },
13427 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013428 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013429 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
13430 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13431 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013432 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13433 .channel_mode = alc662_3ST_2ch_modes,
13434 .input_mux = &alc662_lenovo_101e_capture_source,
13435 .unsol_event = alc662_lenovo_101e_unsol_event,
13436 .init_hook = alc662_lenovo_101e_all_automute,
13437 },
Kailang Yang291702f2007-10-16 14:28:03 +020013438 [ALC662_ASUS_EEEPC_P701] = {
13439 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
13440 .init_verbs = { alc662_init_verbs,
13441 alc662_eeepc_sue_init_verbs },
13442 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13443 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020013444 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13445 .channel_mode = alc662_3ST_2ch_modes,
13446 .input_mux = &alc662_eeepc_capture_source,
13447 .unsol_event = alc662_eeepc_unsol_event,
13448 .init_hook = alc662_eeepc_inithook,
13449 },
Kailang Yang8c427222008-01-10 13:03:59 +010013450 [ALC662_ASUS_EEEPC_EP20] = {
13451 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
13452 alc662_chmode_mixer },
13453 .init_verbs = { alc662_init_verbs,
13454 alc662_eeepc_ep20_sue_init_verbs },
13455 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13456 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010013457 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13458 .channel_mode = alc662_3ST_6ch_modes,
13459 .input_mux = &alc662_lenovo_101e_capture_source,
13460 .unsol_event = alc662_eeepc_ep20_unsol_event,
13461 .init_hook = alc662_eeepc_ep20_inithook,
13462 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013463
13464};
13465
13466
13467/*
13468 * BIOS auto configuration
13469 */
13470
13471/* add playback controls from the parsed DAC table */
13472static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
13473 const struct auto_pin_cfg *cfg)
13474{
13475 char name[32];
13476 static const char *chname[4] = {
13477 "Front", "Surround", NULL /*CLFE*/, "Side"
13478 };
13479 hda_nid_t nid;
13480 int i, err;
13481
13482 for (i = 0; i < cfg->line_outs; i++) {
13483 if (!spec->multiout.dac_nids[i])
13484 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020013485 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013486 if (i == 2) {
13487 /* Center/LFE */
13488 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13489 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013490 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13491 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013492 if (err < 0)
13493 return err;
13494 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13495 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013496 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13497 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013498 if (err < 0)
13499 return err;
13500 err = add_control(spec, ALC_CTL_BIND_MUTE,
13501 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013502 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
13503 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013504 if (err < 0)
13505 return err;
13506 err = add_control(spec, ALC_CTL_BIND_MUTE,
13507 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013508 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
13509 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013510 if (err < 0)
13511 return err;
13512 } else {
13513 sprintf(name, "%s Playback Volume", chname[i]);
13514 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013515 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13516 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013517 if (err < 0)
13518 return err;
13519 sprintf(name, "%s Playback Switch", chname[i]);
13520 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013521 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
13522 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013523 if (err < 0)
13524 return err;
13525 }
13526 }
13527 return 0;
13528}
13529
13530/* add playback controls for speaker and HP outputs */
13531static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
13532 const char *pfx)
13533{
13534 hda_nid_t nid;
13535 int err;
13536 char name[32];
13537
13538 if (!pin)
13539 return 0;
13540
13541 if (alc880_is_fixed_pin(pin)) {
13542 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13543 /* printk("DAC nid=%x\n",nid); */
13544 /* specify the DAC as the extra output */
13545 if (!spec->multiout.hp_nid)
13546 spec->multiout.hp_nid = nid;
13547 else
13548 spec->multiout.extra_out_nid[0] = nid;
13549 /* control HP volume/switch on the output mixer amp */
13550 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13551 sprintf(name, "%s Playback Volume", pfx);
13552 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13553 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13554 if (err < 0)
13555 return err;
13556 sprintf(name, "%s Playback Switch", pfx);
13557 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13558 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
13559 if (err < 0)
13560 return err;
13561 } else if (alc880_is_multi_pin(pin)) {
13562 /* set manual connection */
13563 /* we have only a switch on HP-out PIN */
13564 sprintf(name, "%s Playback Switch", pfx);
13565 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
13566 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
13567 if (err < 0)
13568 return err;
13569 }
13570 return 0;
13571}
13572
13573/* create playback/capture controls for input pins */
13574static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
13575 const struct auto_pin_cfg *cfg)
13576{
13577 struct hda_input_mux *imux = &spec->private_imux;
13578 int i, err, idx;
13579
13580 for (i = 0; i < AUTO_PIN_LAST; i++) {
13581 if (alc880_is_input_pin(cfg->input_pins[i])) {
13582 idx = alc880_input_pin_idx(cfg->input_pins[i]);
13583 err = new_analog_input(spec, cfg->input_pins[i],
13584 auto_pin_cfg_labels[i],
13585 idx, 0x0b);
13586 if (err < 0)
13587 return err;
13588 imux->items[imux->num_items].label =
13589 auto_pin_cfg_labels[i];
13590 imux->items[imux->num_items].index =
13591 alc880_input_pin_idx(cfg->input_pins[i]);
13592 imux->num_items++;
13593 }
13594 }
13595 return 0;
13596}
13597
13598static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
13599 hda_nid_t nid, int pin_type,
13600 int dac_idx)
13601{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013602 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013603 /* need the manual connection? */
13604 if (alc880_is_multi_pin(nid)) {
13605 struct alc_spec *spec = codec->spec;
13606 int idx = alc880_multi_pin_idx(nid);
13607 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
13608 AC_VERB_SET_CONNECT_SEL,
13609 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
13610 }
13611}
13612
13613static void alc662_auto_init_multi_out(struct hda_codec *codec)
13614{
13615 struct alc_spec *spec = codec->spec;
13616 int i;
13617
Kailang Yang8c427222008-01-10 13:03:59 +010013618 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013619 for (i = 0; i <= HDA_SIDE; i++) {
13620 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013621 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013622 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013623 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013624 i);
13625 }
13626}
13627
13628static void alc662_auto_init_hp_out(struct hda_codec *codec)
13629{
13630 struct alc_spec *spec = codec->spec;
13631 hda_nid_t pin;
13632
13633 pin = spec->autocfg.hp_pins[0];
13634 if (pin) /* connect to front */
13635 /* use dac 0 */
13636 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013637 pin = spec->autocfg.speaker_pins[0];
13638 if (pin)
13639 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013640}
13641
13642#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
13643#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
13644
13645static void alc662_auto_init_analog_input(struct hda_codec *codec)
13646{
13647 struct alc_spec *spec = codec->spec;
13648 int i;
13649
13650 for (i = 0; i < AUTO_PIN_LAST; i++) {
13651 hda_nid_t nid = spec->autocfg.input_pins[i];
13652 if (alc662_is_input_pin(nid)) {
13653 snd_hda_codec_write(codec, nid, 0,
13654 AC_VERB_SET_PIN_WIDGET_CONTROL,
13655 (i <= AUTO_PIN_FRONT_MIC ?
13656 PIN_VREF80 : PIN_IN));
13657 if (nid != ALC662_PIN_CD_NID)
13658 snd_hda_codec_write(codec, nid, 0,
13659 AC_VERB_SET_AMP_GAIN_MUTE,
13660 AMP_OUT_MUTE);
13661 }
13662 }
13663}
13664
13665static int alc662_parse_auto_config(struct hda_codec *codec)
13666{
13667 struct alc_spec *spec = codec->spec;
13668 int err;
13669 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
13670
13671 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13672 alc662_ignore);
13673 if (err < 0)
13674 return err;
13675 if (!spec->autocfg.line_outs)
13676 return 0; /* can't find valid BIOS pin config */
13677
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013678 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
13679 if (err < 0)
13680 return err;
13681 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
13682 if (err < 0)
13683 return err;
13684 err = alc662_auto_create_extra_out(spec,
13685 spec->autocfg.speaker_pins[0],
13686 "Speaker");
13687 if (err < 0)
13688 return err;
13689 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
13690 "Headphone");
13691 if (err < 0)
13692 return err;
13693 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
13694 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013695 return err;
13696
13697 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13698
13699 if (spec->autocfg.dig_out_pin)
13700 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
13701
13702 if (spec->kctl_alloc)
13703 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13704
13705 spec->num_mux_defs = 1;
13706 spec->input_mux = &spec->private_imux;
13707
Takashi Iwai8c872862007-06-19 12:11:16 +020013708 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013709 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
13710 spec->num_mixers++;
Takashi Iwai8c872862007-06-19 12:11:16 +020013711 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013712}
13713
13714/* additional initialization for auto-configuration model */
13715static void alc662_auto_init(struct hda_codec *codec)
13716{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013717 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013718 alc662_auto_init_multi_out(codec);
13719 alc662_auto_init_hp_out(codec);
13720 alc662_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013721 if (spec->unsol_event)
13722 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013723}
13724
13725static int patch_alc662(struct hda_codec *codec)
13726{
13727 struct alc_spec *spec;
13728 int err, board_config;
13729
13730 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13731 if (!spec)
13732 return -ENOMEM;
13733
13734 codec->spec = spec;
13735
13736 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
13737 alc662_models,
13738 alc662_cfg_tbl);
13739 if (board_config < 0) {
13740 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
13741 "trying auto-probe from BIOS...\n");
13742 board_config = ALC662_AUTO;
13743 }
13744
13745 if (board_config == ALC662_AUTO) {
13746 /* automatic parse from the BIOS config */
13747 err = alc662_parse_auto_config(codec);
13748 if (err < 0) {
13749 alc_free(codec);
13750 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020013751 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013752 printk(KERN_INFO
13753 "hda_codec: Cannot set up configuration "
13754 "from BIOS. Using base mode...\n");
13755 board_config = ALC662_3ST_2ch_DIG;
13756 }
13757 }
13758
13759 if (board_config != ALC662_AUTO)
13760 setup_preset(spec, &alc662_presets[board_config]);
13761
13762 spec->stream_name_analog = "ALC662 Analog";
13763 spec->stream_analog_playback = &alc662_pcm_analog_playback;
13764 spec->stream_analog_capture = &alc662_pcm_analog_capture;
13765
13766 spec->stream_name_digital = "ALC662 Digital";
13767 spec->stream_digital_playback = &alc662_pcm_digital_playback;
13768 spec->stream_digital_capture = &alc662_pcm_digital_capture;
13769
Takashi Iwaie1406342008-02-11 18:32:32 +010013770 spec->adc_nids = alc662_adc_nids;
13771 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
13772 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013773
Takashi Iwai2134ea42008-01-10 16:53:55 +010013774 spec->vmaster_nid = 0x02;
13775
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013776 codec->patch_ops = alc_patch_ops;
13777 if (board_config == ALC662_AUTO)
13778 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013779#ifdef CONFIG_SND_HDA_POWER_SAVE
13780 if (!spec->loopback.amplist)
13781 spec->loopback.amplist = alc662_loopbacks;
13782#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013783
13784 return 0;
13785}
13786
13787/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070013788 * patch entries
13789 */
13790struct hda_codec_preset snd_hda_preset_realtek[] = {
13791 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013792 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013793 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020013794 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013795 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013796 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013797 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013798 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
13799 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
13800 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013801 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
13802 .patch = patch_alc883 },
13803 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
13804 .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013805 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013806 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013807 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013808 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013809 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013810 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013811 {} /* terminator */
13812};