blob: 0a64d24e7fda787ca0e5979ae9e554985e6f2ecb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <sound/driver.h>
27#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
32#include "hda_codec.h"
33#include "hda_local.h"
34
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 Woithe7cf51e482006-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,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020096 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +020097 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +020098 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +020099 ALC262_ULTRA,
Kailang Yangdf694da2005-12-05 19:42:22 +0100100 ALC262_AUTO,
101 ALC262_MODEL_LAST /* last tag */
102};
103
Kailang Yanga361d842007-06-05 12:30:55 +0200104/* ALC268 models */
105enum {
106 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200107 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200108 ALC268_ACER,
Kailang Yanga361d842007-06-05 12:30:55 +0200109 ALC268_AUTO,
110 ALC268_MODEL_LAST /* last tag */
111};
112
Kailang Yangf6a92242007-12-13 16:52:54 +0100113/* ALC269 models */
114enum {
115 ALC269_BASIC,
116 ALC269_AUTO,
117 ALC269_MODEL_LAST /* last tag */
118};
119
Kailang Yangdf694da2005-12-05 19:42:22 +0100120/* ALC861 models */
121enum {
122 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200123 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100124 ALC861_3ST_DIG,
125 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200126 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200127 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200128 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100129 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100130 ALC861_AUTO,
131 ALC861_MODEL_LAST,
132};
133
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100134/* ALC861-VD models */
135enum {
136 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200137 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100138 ALC861VD_3ST,
139 ALC861VD_3ST_DIG,
140 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200141 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200142 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200143 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100144 ALC861VD_AUTO,
145 ALC861VD_MODEL_LAST,
146};
147
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200148/* ALC662 models */
149enum {
150 ALC662_3ST_2ch_DIG,
151 ALC662_3ST_6ch_DIG,
152 ALC662_3ST_6ch,
153 ALC662_5ST_DIG,
154 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200155 ALC662_ASUS_EEEPC_P701,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200156 ALC662_AUTO,
157 ALC662_MODEL_LAST,
158};
159
Kailang Yangdf694da2005-12-05 19:42:22 +0100160/* ALC882 models */
161enum {
162 ALC882_3ST_DIG,
163 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200164 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200165 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200166 ALC882_TARGA,
167 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200168 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100169 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200170 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200171 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200172 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100173 ALC882_MODEL_LAST,
174};
175
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200176/* ALC883 models */
177enum {
178 ALC883_3ST_2ch_DIG,
179 ALC883_3ST_6ch_DIG,
180 ALC883_3ST_6ch,
181 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200182 ALC883_TARGA_DIG,
183 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200184 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200185 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200186 ALC883_MEDION,
Kailang Yang272a5272007-05-14 11:00:38 +0200187 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100188 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200189 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200190 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200191 ALC888_LENOVO_MS7195_DIG,
192 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200193 ALC888_6ST_HP,
194 ALC888_3ST_HP,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100195 ALC883_MITAC,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200196 ALC883_AUTO,
197 ALC883_MODEL_LAST,
198};
199
Kailang Yangdf694da2005-12-05 19:42:22 +0100200/* for GPIO Poll */
201#define GPIO_MASK 0x03
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203struct alc_spec {
204 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100205 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 unsigned int num_mixers;
207
Kailang Yangdf694da2005-12-05 19:42:22 +0100208 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200209 * don't forget NULL
210 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200211 */
212 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Takashi Iwai16ded522005-06-10 19:58:24 +0200214 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 struct hda_pcm_stream *stream_analog_playback;
216 struct hda_pcm_stream *stream_analog_capture;
217
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200218 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 struct hda_pcm_stream *stream_digital_playback;
220 struct hda_pcm_stream *stream_digital_capture;
221
222 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200223 struct hda_multi_out multiout; /* playback set-up
224 * max_channels, dacs must be set
225 * dig_out_nid and hp_nid are optional
226 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 /* capture */
229 unsigned int num_adc_nids;
230 hda_nid_t *adc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200231 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200234 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 const struct hda_input_mux *input_mux;
236 unsigned int cur_mux[3];
237
238 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100239 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200241 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100244 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200245
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200246 /* dynamic controls, init_verbs and input_mux */
247 struct auto_pin_cfg autocfg;
248 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100249 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200250 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200251 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100252
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100253 /* hooks */
254 void (*init_hook)(struct hda_codec *codec);
255 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
256
Takashi Iwai834be882006-03-01 14:16:17 +0100257 /* for pin sensing */
258 unsigned int sense_updated: 1;
259 unsigned int jack_present: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200260
261#ifdef CONFIG_SND_HDA_POWER_SAVE
262 struct hda_loopback_check loopback;
263#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100264};
265
266/*
267 * configuration template - to be copied to the spec instance
268 */
269struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200270 struct snd_kcontrol_new *mixers[5]; /* should be identical size
271 * with spec
272 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100273 const struct hda_verb *init_verbs[5];
274 unsigned int num_dacs;
275 hda_nid_t *dac_nids;
276 hda_nid_t dig_out_nid; /* optional */
277 hda_nid_t hp_nid; /* optional */
278 unsigned int num_adc_nids;
279 hda_nid_t *adc_nids;
280 hda_nid_t dig_in_nid;
281 unsigned int num_channel_mode;
282 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200283 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200284 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100285 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100286 void (*unsol_event)(struct hda_codec *, unsigned int);
287 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200288#ifdef CONFIG_SND_HDA_POWER_SAVE
289 struct hda_amp_list *loopbacks;
290#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291};
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294/*
295 * input MUX handling
296 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200297static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
298 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
301 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200302 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
303 if (mux_idx >= spec->num_mux_defs)
304 mux_idx = 0;
305 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200308static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
309 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
312 struct alc_spec *spec = codec->spec;
313 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
314
315 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
316 return 0;
317}
318
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200319static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
320 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
322 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
323 struct alc_spec *spec = codec->spec;
324 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200325 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
326 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200327 spec->adc_nids[adc_idx],
328 &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332/*
333 * channel mode setting
334 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200335static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
338 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
339 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100340 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
341 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
343
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200344static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
345 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
348 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100349 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200350 spec->num_channel_mode,
351 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200354static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
355 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
358 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200359 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
360 spec->num_channel_mode,
361 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200362 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200363 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
364 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100368 * Control the mode of pin widget settings via the mixer. "pc" is used
369 * instead of "%" to avoid consequences of accidently treating the % as
370 * being part of a format specifier. Maximum allowed length of a value is
371 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100372 *
373 * Note: some retasking pin complexes seem to ignore requests for input
374 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
375 * are requested. Therefore order this list so that this behaviour will not
376 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200377 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
378 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200379 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100380static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100381 "Mic 50pc bias", "Mic 80pc bias",
382 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100383};
384static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100385 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100386};
387/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200388 * in the pin being assumed to be exclusively an input or an output pin. In
389 * addition, "input" pins may or may not process the mic bias option
390 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
391 * accept requests for bias as of chip versions up to March 2006) and/or
392 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100393 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200394#define ALC_PIN_DIR_IN 0x00
395#define ALC_PIN_DIR_OUT 0x01
396#define ALC_PIN_DIR_INOUT 0x02
397#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
398#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100399
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200400/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100401 * For each direction the minimum and maximum values are given.
402 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200403static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100404 { 0, 2 }, /* ALC_PIN_DIR_IN */
405 { 3, 4 }, /* ALC_PIN_DIR_OUT */
406 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200407 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
408 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100409};
410#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
411#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
412#define alc_pin_mode_n_items(_dir) \
413 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
414
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200415static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
416 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200417{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100418 unsigned int item_num = uinfo->value.enumerated.item;
419 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
420
421 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200422 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100423 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
424
425 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
426 item_num = alc_pin_mode_min(dir);
427 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200428 return 0;
429}
430
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200431static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
432 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200433{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100434 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200435 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
436 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100437 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200438 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200439 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
440 AC_VERB_GET_PIN_WIDGET_CONTROL,
441 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200442
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100443 /* Find enumerated value for current pinctl setting */
444 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200445 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100446 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200447 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100448 return 0;
449}
450
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200451static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100453{
454 signed int change;
455 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
456 hda_nid_t nid = kcontrol->private_value & 0xffff;
457 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
458 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200459 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
460 AC_VERB_GET_PIN_WIDGET_CONTROL,
461 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100462
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200463 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100464 val = alc_pin_mode_min(dir);
465
466 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100467 if (change) {
468 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200469 snd_hda_codec_write_cache(codec, nid, 0,
470 AC_VERB_SET_PIN_WIDGET_CONTROL,
471 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100472
473 /* Also enable the retasking pin's input/output as required
474 * for the requested pin mode. Enum values of 2 or less are
475 * input modes.
476 *
477 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200478 * reduces noise slightly (particularly on input) so we'll
479 * do it. However, having both input and output buffers
480 * enabled simultaneously doesn't seem to be problematic if
481 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100482 */
483 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200484 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
485 HDA_AMP_MUTE, HDA_AMP_MUTE);
486 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
487 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100488 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200489 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
490 HDA_AMP_MUTE, HDA_AMP_MUTE);
491 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
492 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100493 }
494 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200495 return change;
496}
497
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100498#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200499 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100500 .info = alc_pin_mode_info, \
501 .get = alc_pin_mode_get, \
502 .put = alc_pin_mode_put, \
503 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100504
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100505/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
506 * together using a mask with more than one bit set. This control is
507 * currently used only by the ALC260 test model. At this stage they are not
508 * needed for any "production" models.
509 */
510#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200511#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200512
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200513static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
514 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100515{
516 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
517 hda_nid_t nid = kcontrol->private_value & 0xffff;
518 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
519 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200520 unsigned int val = snd_hda_codec_read(codec, nid, 0,
521 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100522
523 *valp = (val & mask) != 0;
524 return 0;
525}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200526static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
527 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100528{
529 signed int change;
530 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
531 hda_nid_t nid = kcontrol->private_value & 0xffff;
532 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
533 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200534 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
535 AC_VERB_GET_GPIO_DATA,
536 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100537
538 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200539 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
540 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100541 gpio_data &= ~mask;
542 else
543 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200544 snd_hda_codec_write_cache(codec, nid, 0,
545 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100546
547 return change;
548}
549#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
550 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
551 .info = alc_gpio_data_info, \
552 .get = alc_gpio_data_get, \
553 .put = alc_gpio_data_put, \
554 .private_value = nid | (mask<<16) }
555#endif /* CONFIG_SND_DEBUG */
556
Jonathan Woithe92621f12006-02-28 11:47:47 +0100557/* A switch control to allow the enabling of the digital IO pins on the
558 * ALC260. This is incredibly simplistic; the intention of this control is
559 * to provide something in the test model allowing digital outputs to be
560 * identified if present. If models are found which can utilise these
561 * outputs a more complete mixer control can be devised for those models if
562 * necessary.
563 */
564#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200565#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200566
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200567static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
568 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100569{
570 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
571 hda_nid_t nid = kcontrol->private_value & 0xffff;
572 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
573 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200574 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100575 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100576
577 *valp = (val & mask) != 0;
578 return 0;
579}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200580static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
581 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100582{
583 signed int change;
584 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
585 hda_nid_t nid = kcontrol->private_value & 0xffff;
586 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
587 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200588 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100589 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200590 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100591
592 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200593 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100594 if (val==0)
595 ctrl_data &= ~mask;
596 else
597 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200598 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
599 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100600
601 return change;
602}
603#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
604 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
605 .info = alc_spdif_ctrl_info, \
606 .get = alc_spdif_ctrl_get, \
607 .put = alc_spdif_ctrl_put, \
608 .private_value = nid | (mask<<16) }
609#endif /* CONFIG_SND_DEBUG */
610
Jonathan Woithef8225f62008-01-08 12:16:54 +0100611/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
612 * Again, this is only used in the ALC26x test models to help identify when
613 * the EAPD line must be asserted for features to work.
614 */
615#ifdef CONFIG_SND_DEBUG
616#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
617
618static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
619 struct snd_ctl_elem_value *ucontrol)
620{
621 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
622 hda_nid_t nid = kcontrol->private_value & 0xffff;
623 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
624 long *valp = ucontrol->value.integer.value;
625 unsigned int val = snd_hda_codec_read(codec, nid, 0,
626 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
627
628 *valp = (val & mask) != 0;
629 return 0;
630}
631
632static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
633 struct snd_ctl_elem_value *ucontrol)
634{
635 int change;
636 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
637 hda_nid_t nid = kcontrol->private_value & 0xffff;
638 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
639 long val = *ucontrol->value.integer.value;
640 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
641 AC_VERB_GET_EAPD_BTLENABLE,
642 0x00);
643
644 /* Set/unset the masked control bit(s) as needed */
645 change = (!val ? 0 : mask) != (ctrl_data & mask);
646 if (!val)
647 ctrl_data &= ~mask;
648 else
649 ctrl_data |= mask;
650 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
651 ctrl_data);
652
653 return change;
654}
655
656#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
657 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
658 .info = alc_eapd_ctrl_info, \
659 .get = alc_eapd_ctrl_get, \
660 .put = alc_eapd_ctrl_put, \
661 .private_value = nid | (mask<<16) }
662#endif /* CONFIG_SND_DEBUG */
663
Kailang Yangdf694da2005-12-05 19:42:22 +0100664/*
665 * set up from the preset table
666 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200667static void setup_preset(struct alc_spec *spec,
668 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100669{
670 int i;
671
672 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
673 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200674 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
675 i++)
676 spec->init_verbs[spec->num_init_verbs++] =
677 preset->init_verbs[i];
Kailang Yangdf694da2005-12-05 19:42:22 +0100678
679 spec->channel_mode = preset->channel_mode;
680 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200681 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100682
683 spec->multiout.max_channels = spec->channel_mode[0].channels;
684
685 spec->multiout.num_dacs = preset->num_dacs;
686 spec->multiout.dac_nids = preset->dac_nids;
687 spec->multiout.dig_out_nid = preset->dig_out_nid;
688 spec->multiout.hp_nid = preset->hp_nid;
689
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200690 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200691 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200692 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100693 spec->input_mux = preset->input_mux;
694
695 spec->num_adc_nids = preset->num_adc_nids;
696 spec->adc_nids = preset->adc_nids;
697 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100698
699 spec->unsol_event = preset->unsol_event;
700 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200701#ifdef CONFIG_SND_HDA_POWER_SAVE
702 spec->loopback.amplist = preset->loopbacks;
703#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100704}
705
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200706/* Enable GPIO mask and set output */
707static struct hda_verb alc_gpio1_init_verbs[] = {
708 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
709 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
710 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
711 { }
712};
713
714static struct hda_verb alc_gpio2_init_verbs[] = {
715 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
716 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
717 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
718 { }
719};
720
Kailang Yangbdd148a2007-05-08 15:19:08 +0200721static struct hda_verb alc_gpio3_init_verbs[] = {
722 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
723 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
724 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
725 { }
726};
727
Kailang Yangc9b58002007-10-16 14:30:01 +0200728static void alc_sku_automute(struct hda_codec *codec)
729{
730 struct alc_spec *spec = codec->spec;
731 unsigned int mute;
732 unsigned int present;
733 unsigned int hp_nid = spec->autocfg.hp_pins[0];
734 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
735
736 /* need to execute and sync at first */
737 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
738 present = snd_hda_codec_read(codec, hp_nid, 0,
739 AC_VERB_GET_PIN_SENSE, 0);
740 spec->jack_present = (present & 0x80000000) != 0;
741 if (spec->jack_present) {
742 /* mute internal speaker */
743 snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
744 HDA_AMP_MUTE, HDA_AMP_MUTE);
745 } else {
746 /* unmute internal speaker if necessary */
747 mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
748 snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
749 HDA_AMP_MUTE, mute);
750 }
751}
752
753/* unsolicited event for HP jack sensing */
754static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
755{
756 if (codec->vendor_id == 0x10ec0880)
757 res >>= 28;
758 else
759 res >>= 26;
760 if (res != ALC880_HP_EVENT)
761 return;
762
763 alc_sku_automute(codec);
764}
765
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200766/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
767 * 31 ~ 16 : Manufacture ID
768 * 15 ~ 8 : SKU ID
769 * 7 ~ 0 : Assembly ID
770 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
771 */
772static void alc_subsystem_id(struct hda_codec *codec,
773 unsigned int porta, unsigned int porte,
774 unsigned int portd)
775{
Kailang Yangc9b58002007-10-16 14:30:01 +0200776 unsigned int ass, tmp, i;
777 unsigned nid;
778 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200779
Kailang Yangc9b58002007-10-16 14:30:01 +0200780 ass = codec->subsystem_id & 0xffff;
781 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
782 goto do_sku;
783
784 /*
785 * 31~30 : port conetcivity
786 * 29~21 : reserve
787 * 20 : PCBEEP input
788 * 19~16 : Check sum (15:1)
789 * 15~1 : Custom
790 * 0 : override
791 */
792 nid = 0x1d;
793 if (codec->vendor_id == 0x10ec0260)
794 nid = 0x17;
795 ass = snd_hda_codec_read(codec, nid, 0,
796 AC_VERB_GET_CONFIG_DEFAULT, 0);
797 if (!(ass & 1) && !(ass & 0x100000))
798 return;
799 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200800 return;
801
Kailang Yangc9b58002007-10-16 14:30:01 +0200802 /* check sum */
803 tmp = 0;
804 for (i = 1; i < 16; i++) {
805 if ((ass >> i) && 1)
806 tmp++;
807 }
808 if (((ass >> 16) & 0xf) != tmp)
809 return;
810do_sku:
811 /*
812 * 0 : override
813 * 1 : Swap Jack
814 * 2 : 0 --> Desktop, 1 --> Laptop
815 * 3~5 : External Amplifier control
816 * 7~6 : Reserved
817 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200818 tmp = (ass & 0x38) >> 3; /* external Amp control */
819 switch (tmp) {
820 case 1:
821 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
822 break;
823 case 3:
824 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
825 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200826 case 7:
827 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
828 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200829 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200830 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200831 case 0x10ec0260:
832 snd_hda_codec_write(codec, 0x0f, 0,
833 AC_VERB_SET_EAPD_BTLENABLE, 2);
834 snd_hda_codec_write(codec, 0x10, 0,
835 AC_VERB_SET_EAPD_BTLENABLE, 2);
836 break;
837 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200838 case 0x10ec0267:
839 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200840 case 0x10ec0269:
841 case 0x10ec0862:
842 case 0x10ec0662:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200843 snd_hda_codec_write(codec, 0x14, 0,
844 AC_VERB_SET_EAPD_BTLENABLE, 2);
845 snd_hda_codec_write(codec, 0x15, 0,
846 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200847 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200848 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200849 switch (codec->vendor_id) {
850 case 0x10ec0260:
851 snd_hda_codec_write(codec, 0x1a, 0,
852 AC_VERB_SET_COEF_INDEX, 7);
853 tmp = snd_hda_codec_read(codec, 0x1a, 0,
854 AC_VERB_GET_PROC_COEF, 0);
855 snd_hda_codec_write(codec, 0x1a, 0,
856 AC_VERB_SET_COEF_INDEX, 7);
857 snd_hda_codec_write(codec, 0x1a, 0,
858 AC_VERB_SET_PROC_COEF,
859 tmp | 0x2010);
860 break;
861 case 0x10ec0262:
862 case 0x10ec0880:
863 case 0x10ec0882:
864 case 0x10ec0883:
865 case 0x10ec0885:
866 case 0x10ec0888:
867 snd_hda_codec_write(codec, 0x20, 0,
868 AC_VERB_SET_COEF_INDEX, 7);
869 tmp = snd_hda_codec_read(codec, 0x20, 0,
870 AC_VERB_GET_PROC_COEF, 0);
871 snd_hda_codec_write(codec, 0x20, 0,
872 AC_VERB_SET_COEF_INDEX, 7);
873 snd_hda_codec_write(codec, 0x20, 0,
874 AC_VERB_SET_PROC_COEF,
875 tmp | 0x2010);
876 break;
877 case 0x10ec0267:
878 case 0x10ec0268:
879 snd_hda_codec_write(codec, 0x20, 0,
880 AC_VERB_SET_COEF_INDEX, 7);
881 tmp = snd_hda_codec_read(codec, 0x20, 0,
882 AC_VERB_GET_PROC_COEF, 0);
883 snd_hda_codec_write(codec, 0x20, 0,
884 AC_VERB_SET_COEF_INDEX, 7);
885 snd_hda_codec_write(codec, 0x20, 0,
886 AC_VERB_SET_PROC_COEF,
887 tmp | 0x3000);
888 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200889 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200890 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200891 break;
892 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200893
894 /* is laptop and enable the function "Mute internal speaker
895 * when the external headphone out jack is plugged"
896 */
897 if (!(ass & 0x4) || !(ass & 0x8000))
898 return;
899 /*
900 * 10~8 : Jack location
901 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
902 * 14~13: Resvered
903 * 15 : 1 --> enable the function "Mute internal speaker
904 * when the external headphone out jack is plugged"
905 */
906 if (!spec->autocfg.speaker_pins[0]) {
907 if (spec->multiout.dac_nids[0])
908 spec->autocfg.speaker_pins[0] =
909 spec->multiout.dac_nids[0];
910 else
911 return;
912 }
913
914 if (!spec->autocfg.hp_pins[0]) {
915 tmp = (ass >> 11) & 0x3; /* HP to chassis */
916 if (tmp == 0)
917 spec->autocfg.hp_pins[0] = porta;
918 else if (tmp == 1)
919 spec->autocfg.hp_pins[0] = porte;
920 else if (tmp == 2)
921 spec->autocfg.hp_pins[0] = portd;
922 else
923 return;
924 }
925
926 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
927 AC_VERB_SET_UNSOLICITED_ENABLE,
928 AC_USRSP_EN | ALC880_HP_EVENT);
929 spec->unsol_event = alc_sku_unsol_event;
930 spec->init_hook = alc_sku_automute;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200931}
932
Takashi Iwai41e41f12005-06-08 14:48:49 +0200933/*
Takashi Iwaif95474e2007-07-10 00:47:43 +0200934 * Fix-up pin default configurations
935 */
936
937struct alc_pincfg {
938 hda_nid_t nid;
939 u32 val;
940};
941
942static void alc_fix_pincfg(struct hda_codec *codec,
943 const struct snd_pci_quirk *quirk,
944 const struct alc_pincfg **pinfix)
945{
946 const struct alc_pincfg *cfg;
947
948 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
949 if (!quirk)
950 return;
951
952 cfg = pinfix[quirk->value];
953 for (; cfg->nid; cfg++) {
954 int i;
955 u32 val = cfg->val;
956 for (i = 0; i < 4; i++) {
957 snd_hda_codec_write(codec, cfg->nid, 0,
958 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
959 val & 0xff);
960 val >>= 8;
961 }
962 }
963}
964
965/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200966 * ALC880 3-stack model
967 *
968 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200969 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
970 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 */
972
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200973static hda_nid_t alc880_dac_nids[4] = {
974 /* front, rear, clfe, rear_surr */
975 0x02, 0x05, 0x04, 0x03
976};
977
978static hda_nid_t alc880_adc_nids[3] = {
979 /* ADC0-2 */
980 0x07, 0x08, 0x09,
981};
982
983/* The datasheet says the node 0x07 is connected from inputs,
984 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +0100985 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200987static hda_nid_t alc880_adc_nids_alt[2] = {
988 /* ADC1-2 */
989 0x08, 0x09,
990};
991
992#define ALC880_DIGOUT_NID 0x06
993#define ALC880_DIGIN_NID 0x0a
994
995static struct hda_input_mux alc880_capture_source = {
996 .num_items = 4,
997 .items = {
998 { "Mic", 0x0 },
999 { "Front Mic", 0x3 },
1000 { "Line", 0x2 },
1001 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001003};
1004
1005/* channel source setting (2/6 channel selection for 3-stack) */
1006/* 2ch mode */
1007static struct hda_verb alc880_threestack_ch2_init[] = {
1008 /* set line-in to input, mute it */
1009 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1010 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1011 /* set mic-in to input vref 80%, mute it */
1012 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1013 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 { } /* end */
1015};
1016
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001017/* 6ch mode */
1018static struct hda_verb alc880_threestack_ch6_init[] = {
1019 /* set line-in to output, unmute it */
1020 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1021 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1022 /* set mic-in to output, unmute it */
1023 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1024 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1025 { } /* end */
1026};
1027
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001028static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001029 { 2, alc880_threestack_ch2_init },
1030 { 6, alc880_threestack_ch6_init },
1031};
1032
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001033static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001034 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001035 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001036 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001037 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001038 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1039 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001040 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1041 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1043 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1044 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1045 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1046 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1047 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1048 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1049 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1050 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1051 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001053 {
1054 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1055 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001056 .info = alc_ch_mode_info,
1057 .get = alc_ch_mode_get,
1058 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001059 },
1060 { } /* end */
1061};
1062
1063/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001064static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001065 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1066 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1067 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1068 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1069 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1070 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1071 {
1072 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1073 /* The multiple "Capture Source" controls confuse alsamixer
1074 * So call somewhat different..
1075 * FIXME: the controls appear in the "playback" view!
1076 */
1077 /* .name = "Capture Source", */
1078 .name = "Input Source",
1079 .count = 3,
1080 .info = alc_mux_enum_info,
1081 .get = alc_mux_enum_get,
1082 .put = alc_mux_enum_put,
1083 },
1084 { } /* end */
1085};
1086
1087/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001088static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001089 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1090 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1091 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1092 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 {
1094 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1095 /* The multiple "Capture Source" controls confuse alsamixer
1096 * So call somewhat different..
1097 * FIXME: the controls appear in the "playback" view!
1098 */
1099 /* .name = "Capture Source", */
1100 .name = "Input Source",
1101 .count = 2,
1102 .info = alc_mux_enum_info,
1103 .get = alc_mux_enum_get,
1104 .put = alc_mux_enum_put,
1105 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 { } /* end */
1107};
1108
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001109
1110
1111/*
1112 * ALC880 5-stack model
1113 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001114 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1115 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001116 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1117 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1118 */
1119
1120/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001121static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001122 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001123 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 { } /* end */
1125};
1126
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001127/* channel source setting (6/8 channel selection for 5-stack) */
1128/* 6ch mode */
1129static struct hda_verb alc880_fivestack_ch6_init[] = {
1130 /* set line-in to input, mute it */
1131 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1132 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001133 { } /* end */
1134};
1135
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001136/* 8ch mode */
1137static struct hda_verb alc880_fivestack_ch8_init[] = {
1138 /* set line-in to output, unmute it */
1139 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1140 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1141 { } /* end */
1142};
1143
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001144static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001145 { 6, alc880_fivestack_ch6_init },
1146 { 8, alc880_fivestack_ch8_init },
1147};
1148
1149
1150/*
1151 * ALC880 6-stack model
1152 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001153 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1154 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001155 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1156 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1157 */
1158
1159static hda_nid_t alc880_6st_dac_nids[4] = {
1160 /* front, rear, clfe, rear_surr */
1161 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001162};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001163
1164static struct hda_input_mux alc880_6stack_capture_source = {
1165 .num_items = 4,
1166 .items = {
1167 { "Mic", 0x0 },
1168 { "Front Mic", 0x1 },
1169 { "Line", 0x2 },
1170 { "CD", 0x4 },
1171 },
1172};
1173
1174/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001175static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001176 { 8, NULL },
1177};
1178
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001179static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001180 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001181 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001182 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001183 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001184 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1185 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001186 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1187 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001188 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001189 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001190 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1191 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1192 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1193 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1194 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1195 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1196 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1197 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1198 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1199 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001200 {
1201 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1202 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001203 .info = alc_ch_mode_info,
1204 .get = alc_ch_mode_get,
1205 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001206 },
1207 { } /* end */
1208};
1209
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001210
1211/*
1212 * ALC880 W810 model
1213 *
1214 * W810 has rear IO for:
1215 * Front (DAC 02)
1216 * Surround (DAC 03)
1217 * Center/LFE (DAC 04)
1218 * Digital out (06)
1219 *
1220 * The system also has a pair of internal speakers, and a headphone jack.
1221 * These are both connected to Line2 on the codec, hence to DAC 02.
1222 *
1223 * There is a variable resistor to control the speaker or headphone
1224 * volume. This is a hardware-only device without a software API.
1225 *
1226 * Plugging headphones in will disable the internal speakers. This is
1227 * implemented in hardware, not via the driver using jack sense. In
1228 * a similar fashion, plugging into the rear socket marked "front" will
1229 * disable both the speakers and headphones.
1230 *
1231 * For input, there's a microphone jack, and an "audio in" jack.
1232 * These may not do anything useful with this driver yet, because I
1233 * haven't setup any initialization verbs for these yet...
1234 */
1235
1236static hda_nid_t alc880_w810_dac_nids[3] = {
1237 /* front, rear/surround, clfe */
1238 0x02, 0x03, 0x04
1239};
1240
1241/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001242static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001243 { 6, NULL }
1244};
1245
1246/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001247static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001249 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001250 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001251 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001252 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1253 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001254 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1255 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001256 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1257 { } /* end */
1258};
1259
1260
1261/*
1262 * Z710V model
1263 *
1264 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001265 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1266 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001267 */
1268
1269static hda_nid_t alc880_z71v_dac_nids[1] = {
1270 0x02
1271};
1272#define ALC880_Z71V_HP_DAC 0x03
1273
1274/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001275static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001276 { 2, NULL }
1277};
1278
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001279static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001280 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001281 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001282 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001283 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001284 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1285 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1286 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1287 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1288 { } /* end */
1289};
1290
1291
1292/* FIXME! */
1293/*
1294 * ALC880 F1734 model
1295 *
1296 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1297 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1298 */
1299
1300static hda_nid_t alc880_f1734_dac_nids[1] = {
1301 0x03
1302};
1303#define ALC880_F1734_HP_DAC 0x02
1304
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001305static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001306 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001307 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001308 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001309 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001310 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1311 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1312 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1313 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001314 { } /* end */
1315};
1316
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001317
1318/* FIXME! */
1319/*
1320 * ALC880 ASUS model
1321 *
1322 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1323 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1324 * Mic = 0x18, Line = 0x1a
1325 */
1326
1327#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1328#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1329
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001330static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001331 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001332 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001333 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001334 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001335 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1336 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001337 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1338 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001339 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1340 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1341 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1342 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1343 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1344 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001345 {
1346 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1347 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001348 .info = alc_ch_mode_info,
1349 .get = alc_ch_mode_get,
1350 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001351 },
1352 { } /* end */
1353};
1354
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001355/* FIXME! */
1356/*
1357 * ALC880 ASUS W1V model
1358 *
1359 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1360 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1361 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1362 */
1363
1364/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001365static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001366 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1367 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001368 { } /* end */
1369};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001370
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001371/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001372static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001373 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1374 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1375 { } /* end */
1376};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001377
Kailang Yangdf694da2005-12-05 19:42:22 +01001378/* TCL S700 */
1379static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1380 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1381 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1382 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1383 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1384 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1385 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1386 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1387 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1388 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1389 {
1390 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1391 /* The multiple "Capture Source" controls confuse alsamixer
1392 * So call somewhat different..
1393 * FIXME: the controls appear in the "playback" view!
1394 */
1395 /* .name = "Capture Source", */
1396 .name = "Input Source",
1397 .count = 1,
1398 .info = alc_mux_enum_info,
1399 .get = alc_mux_enum_get,
1400 .put = alc_mux_enum_put,
1401 },
1402 { } /* end */
1403};
1404
Kailang Yangccc656c2006-10-17 12:32:26 +02001405/* Uniwill */
1406static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
1407 HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1408 HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
1409 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1410 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
1411 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1412 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1413 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1414 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1415 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1416 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1417 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1418 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1419 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1420 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1421 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1422 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1423 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1424 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1425 {
1426 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1427 .name = "Channel Mode",
1428 .info = alc_ch_mode_info,
1429 .get = alc_ch_mode_get,
1430 .put = alc_ch_mode_put,
1431 },
1432 { } /* end */
1433};
1434
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001435static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1436 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1437 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1438 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1439 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1440 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1441 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1442 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1443 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1444 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1445 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1446 { } /* end */
1447};
1448
Kailang Yangccc656c2006-10-17 12:32:26 +02001449static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
1450 HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1451 HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
1452 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1453 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
1454 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1455 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1456 { } /* end */
1457};
1458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001460 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 */
1462static int alc_build_controls(struct hda_codec *codec)
1463{
1464 struct alc_spec *spec = codec->spec;
1465 int err;
1466 int i;
1467
1468 for (i = 0; i < spec->num_mixers; i++) {
1469 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1470 if (err < 0)
1471 return err;
1472 }
1473
1474 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001475 err = snd_hda_create_spdif_out_ctls(codec,
1476 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if (err < 0)
1478 return err;
1479 }
1480 if (spec->dig_in_nid) {
1481 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1482 if (err < 0)
1483 return err;
1484 }
1485 return 0;
1486}
1487
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489/*
1490 * initialize the codec volumes, etc
1491 */
1492
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001493/*
1494 * generic initialization of ADC, input mixers and output mixers
1495 */
1496static struct hda_verb alc880_volume_init_verbs[] = {
1497 /*
1498 * Unmute ADC0-2 and set the default input to mic-in
1499 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001500 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001501 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001502 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001503 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001504 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001505 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001507 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1508 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001509 * Note: PASD motherboards uses the Line In 2 as the input for front
1510 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001512 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001513 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1514 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1515 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1516 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1517 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1518 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1519 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001521 /*
1522 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001524 /* set vol=0 to output mixers */
1525 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1526 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1527 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1528 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1529 /* set up input amps for analog loopback */
1530 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001531 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1532 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001533 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1534 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001535 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1536 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001537 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1538 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
1540 { }
1541};
1542
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001543/*
1544 * 3-stack pin configuration:
1545 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1546 */
1547static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1548 /*
1549 * preset connection lists of input pins
1550 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1551 */
1552 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1553 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1554 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1555
1556 /*
1557 * Set pin mode and muting
1558 */
1559 /* set front pin widgets 0x14 for output */
1560 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1561 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1562 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1563 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1564 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1565 /* Mic2 (as headphone out) for HP output */
1566 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1567 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1568 /* Line In pin widget for input */
1569 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1570 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1571 /* Line2 (as front mic) pin widget for input and vref at 80% */
1572 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1573 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1574 /* CD pin widget for input */
1575 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1576
1577 { }
1578};
1579
1580/*
1581 * 5-stack pin configuration:
1582 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1583 * line-in/side = 0x1a, f-mic = 0x1b
1584 */
1585static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1586 /*
1587 * preset connection lists of input pins
1588 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1589 */
1590 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1591 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1592
1593 /*
1594 * Set pin mode and muting
1595 */
1596 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001597 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1598 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1599 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1600 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001601 /* unmute pins for output (no gain on this amp) */
1602 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1603 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1604 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1605 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001608 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001609 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1610 /* Mic2 (as headphone out) for HP output */
1611 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001612 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001613 /* Line In pin widget for input */
1614 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1615 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1616 /* Line2 (as front mic) pin widget for input and vref at 80% */
1617 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1618 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1619 /* CD pin widget for input */
1620 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 { }
1623};
1624
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001625/*
1626 * W810 pin configuration:
1627 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1628 */
1629static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 /* hphone/speaker input selector: front DAC */
1631 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1632
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001633 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1634 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1635 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1636 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1637 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1638 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1639
1640 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001641 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 { }
1644};
1645
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001646/*
1647 * Z71V pin configuration:
1648 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1649 */
1650static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001651 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001652 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001653 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001654 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001655
Takashi Iwai16ded522005-06-10 19:58:24 +02001656 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001657 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001658 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001659 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001660
1661 { }
1662};
1663
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001664/*
1665 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001666 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1667 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001668 */
1669static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1670 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1671
Takashi Iwai16ded522005-06-10 19:58:24 +02001672 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001673 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001674 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001675 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001676 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001677 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001678 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001679 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1680
Takashi Iwai16ded522005-06-10 19:58:24 +02001681 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001682 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001683 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001684 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001685 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001686 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001687 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001688 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001689 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1690
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001691 { }
1692};
Takashi Iwai16ded522005-06-10 19:58:24 +02001693
Kailang Yangccc656c2006-10-17 12:32:26 +02001694/*
1695 * Uniwill pin configuration:
1696 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1697 * line = 0x1a
1698 */
1699static struct hda_verb alc880_uniwill_init_verbs[] = {
1700 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1701
1702 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1703 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1704 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1705 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1706 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1707 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1708 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1709 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1710 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1711 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1712 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1713 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1714 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1715 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1716
1717 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1718 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1719 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1720 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1721 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1722 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1723 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1724 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1725 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1726
1727 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1728 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1729
1730 { }
1731};
1732
1733/*
1734* Uniwill P53
1735* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1736 */
1737static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1738 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1739
1740 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1741 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1742 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1743 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1744 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1745 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1747 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1748 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1750 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1751 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1752
1753 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1754 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1755 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1756 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1757 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1758 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1759
1760 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1761 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1762
1763 { }
1764};
1765
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001766static struct hda_verb alc880_beep_init_verbs[] = {
1767 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1768 { }
1769};
1770
Kailang Yangccc656c2006-10-17 12:32:26 +02001771/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001772static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001773{
1774 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001775 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001776
1777 present = snd_hda_codec_read(codec, 0x14, 0,
1778 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001779 bits = present ? HDA_AMP_MUTE : 0;
1780 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1781 HDA_AMP_MUTE, bits);
1782 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1783 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001784}
1785
1786/* auto-toggle front mic */
1787static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1788{
1789 unsigned int present;
1790 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001791
1792 present = snd_hda_codec_read(codec, 0x18, 0,
1793 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001794 bits = present ? HDA_AMP_MUTE : 0;
1795 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001796}
1797
1798static void alc880_uniwill_automute(struct hda_codec *codec)
1799{
1800 alc880_uniwill_hp_automute(codec);
1801 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001802}
1803
1804static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1805 unsigned int res)
1806{
1807 /* Looks like the unsol event is incompatible with the standard
1808 * definition. 4bit tag is placed at 28 bit!
1809 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001810 switch (res >> 28) {
1811 case ALC880_HP_EVENT:
1812 alc880_uniwill_hp_automute(codec);
1813 break;
1814 case ALC880_MIC_EVENT:
1815 alc880_uniwill_mic_automute(codec);
1816 break;
1817 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001818}
1819
1820static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1821{
1822 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001823 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001824
1825 present = snd_hda_codec_read(codec, 0x14, 0,
1826 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001827 bits = present ? HDA_AMP_MUTE : 0;
1828 snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001829}
1830
1831static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1832{
1833 unsigned int present;
1834
1835 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001836 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1837 present &= HDA_AMP_VOLMASK;
1838 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1839 HDA_AMP_VOLMASK, present);
1840 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1841 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001842}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001843
Kailang Yangccc656c2006-10-17 12:32:26 +02001844static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1845 unsigned int res)
1846{
1847 /* Looks like the unsol event is incompatible with the standard
1848 * definition. 4bit tag is placed at 28 bit!
1849 */
1850 if ((res >> 28) == ALC880_HP_EVENT)
1851 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001852 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001853 alc880_uniwill_p53_dcvol_automute(codec);
1854}
1855
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001856/* FIXME! */
1857/*
1858 * F1734 pin configuration:
1859 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1860 */
1861static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1862 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1863 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1864 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1865 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1866
1867 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1868 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1869 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1870 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1871
1872 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1873 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1874 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1875 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1876 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1877 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1878 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1879 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1880 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001881
1882 { }
1883};
1884
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001885/* FIXME! */
1886/*
1887 * ASUS pin configuration:
1888 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1889 */
1890static struct hda_verb alc880_pin_asus_init_verbs[] = {
1891 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1892 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1893 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1894 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1895
1896 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1897 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1898 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1899 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1900 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1901 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1902 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1903 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1904
1905 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1906 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1907 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1908 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1909 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1910 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1911 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1912 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1913 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1914
1915 { }
1916};
1917
1918/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001919#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1920#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001921
Kailang Yangdf694da2005-12-05 19:42:22 +01001922/* Clevo m520g init */
1923static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1924 /* headphone output */
1925 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1926 /* line-out */
1927 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1928 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1929 /* Line-in */
1930 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1931 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1932 /* CD */
1933 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1934 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1935 /* Mic1 (rear panel) */
1936 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1937 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1938 /* Mic2 (front panel) */
1939 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1940 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1941 /* headphone */
1942 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1943 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1944 /* change to EAPD mode */
1945 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1946 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
1947
1948 { }
1949};
1950
1951static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02001952 /* change to EAPD mode */
1953 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1954 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
1955
Kailang Yangdf694da2005-12-05 19:42:22 +01001956 /* Headphone output */
1957 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1958 /* Front output*/
1959 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1960 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1961
1962 /* Line In pin widget for input */
1963 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1964 /* CD pin widget for input */
1965 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1966 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1967 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1968
1969 /* change to EAPD mode */
1970 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1971 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
1972
1973 { }
1974};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001975
1976/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01001977 * LG m1 express dual
1978 *
1979 * Pin assignment:
1980 * Rear Line-In/Out (blue): 0x14
1981 * Build-in Mic-In: 0x15
1982 * Speaker-out: 0x17
1983 * HP-Out (green): 0x1b
1984 * Mic-In/Out (red): 0x19
1985 * SPDIF-Out: 0x1e
1986 */
1987
1988/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
1989static hda_nid_t alc880_lg_dac_nids[3] = {
1990 0x05, 0x02, 0x03
1991};
1992
1993/* seems analog CD is not working */
1994static struct hda_input_mux alc880_lg_capture_source = {
1995 .num_items = 3,
1996 .items = {
1997 { "Mic", 0x1 },
1998 { "Line", 0x5 },
1999 { "Internal Mic", 0x6 },
2000 },
2001};
2002
2003/* 2,4,6 channel modes */
2004static struct hda_verb alc880_lg_ch2_init[] = {
2005 /* set line-in and mic-in to input */
2006 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2007 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2008 { }
2009};
2010
2011static struct hda_verb alc880_lg_ch4_init[] = {
2012 /* set line-in to out and mic-in to input */
2013 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2014 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2015 { }
2016};
2017
2018static struct hda_verb alc880_lg_ch6_init[] = {
2019 /* set line-in and mic-in to output */
2020 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2021 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2022 { }
2023};
2024
2025static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2026 { 2, alc880_lg_ch2_init },
2027 { 4, alc880_lg_ch4_init },
2028 { 6, alc880_lg_ch6_init },
2029};
2030
2031static struct snd_kcontrol_new alc880_lg_mixer[] = {
2032 /* FIXME: it's not really "master" but front channels */
2033 HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2034 HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT),
2035 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2036 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2037 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2038 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2039 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2040 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2041 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2042 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2043 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2044 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2045 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2046 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2047 {
2048 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2049 .name = "Channel Mode",
2050 .info = alc_ch_mode_info,
2051 .get = alc_ch_mode_get,
2052 .put = alc_ch_mode_put,
2053 },
2054 { } /* end */
2055};
2056
2057static struct hda_verb alc880_lg_init_verbs[] = {
2058 /* set capture source to mic-in */
2059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2060 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2061 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2062 /* mute all amp mixer inputs */
2063 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002064 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2065 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002066 /* line-in to input */
2067 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2068 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2069 /* built-in mic */
2070 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2071 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2072 /* speaker-out */
2073 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2074 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2075 /* mic-in to input */
2076 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2077 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2078 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2079 /* HP-out */
2080 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2081 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2082 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2083 /* jack sense */
2084 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2085 { }
2086};
2087
2088/* toggle speaker-output according to the hp-jack state */
2089static void alc880_lg_automute(struct hda_codec *codec)
2090{
2091 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002092 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002093
2094 present = snd_hda_codec_read(codec, 0x1b, 0,
2095 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002096 bits = present ? HDA_AMP_MUTE : 0;
2097 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2098 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002099}
2100
2101static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2102{
2103 /* Looks like the unsol event is incompatible with the standard
2104 * definition. 4bit tag is placed at 28 bit!
2105 */
2106 if ((res >> 28) == 0x01)
2107 alc880_lg_automute(codec);
2108}
2109
2110/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002111 * LG LW20
2112 *
2113 * Pin assignment:
2114 * Speaker-out: 0x14
2115 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002116 * Built-in Mic-In: 0x19
2117 * Line-In: 0x1b
2118 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002119 * SPDIF-Out: 0x1e
2120 */
2121
Takashi Iwaid6815182006-03-23 16:06:23 +01002122static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002123 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002124 .items = {
2125 { "Mic", 0x0 },
2126 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002127 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002128 },
2129};
2130
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002131#define alc880_lg_lw_modes alc880_threestack_modes
2132
Takashi Iwaid6815182006-03-23 16:06:23 +01002133static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002134 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2135 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2136 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2137 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2138 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2139 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2140 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2141 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2142 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2143 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002144 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2145 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2146 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2147 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002148 {
2149 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2150 .name = "Channel Mode",
2151 .info = alc_ch_mode_info,
2152 .get = alc_ch_mode_get,
2153 .put = alc_ch_mode_put,
2154 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002155 { } /* end */
2156};
2157
2158static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002159 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2160 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2161 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2162
Takashi Iwaid6815182006-03-23 16:06:23 +01002163 /* set capture source to mic-in */
2164 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2165 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2166 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002167 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002168 /* speaker-out */
2169 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2170 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2171 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002172 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2173 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2174 /* mic-in to input */
2175 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2176 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2177 /* built-in mic */
2178 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2179 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2180 /* jack sense */
2181 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2182 { }
2183};
2184
2185/* toggle speaker-output according to the hp-jack state */
2186static void alc880_lg_lw_automute(struct hda_codec *codec)
2187{
2188 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002189 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002190
2191 present = snd_hda_codec_read(codec, 0x1b, 0,
2192 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002193 bits = present ? HDA_AMP_MUTE : 0;
2194 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2195 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002196}
2197
2198static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2199{
2200 /* Looks like the unsol event is incompatible with the standard
2201 * definition. 4bit tag is placed at 28 bit!
2202 */
2203 if ((res >> 28) == 0x01)
2204 alc880_lg_lw_automute(codec);
2205}
2206
Takashi Iwaicb53c622007-08-10 17:21:45 +02002207#ifdef CONFIG_SND_HDA_POWER_SAVE
2208static struct hda_amp_list alc880_loopbacks[] = {
2209 { 0x0b, HDA_INPUT, 0 },
2210 { 0x0b, HDA_INPUT, 1 },
2211 { 0x0b, HDA_INPUT, 2 },
2212 { 0x0b, HDA_INPUT, 3 },
2213 { 0x0b, HDA_INPUT, 4 },
2214 { } /* end */
2215};
2216
2217static struct hda_amp_list alc880_lg_loopbacks[] = {
2218 { 0x0b, HDA_INPUT, 1 },
2219 { 0x0b, HDA_INPUT, 6 },
2220 { 0x0b, HDA_INPUT, 7 },
2221 { } /* end */
2222};
2223#endif
2224
Takashi Iwaid6815182006-03-23 16:06:23 +01002225/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002226 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002227 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229static int alc_init(struct hda_codec *codec)
2230{
2231 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002232 unsigned int i;
2233
2234 for (i = 0; i < spec->num_init_verbs; i++)
2235 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002236
2237 if (spec->init_hook)
2238 spec->init_hook(codec);
2239
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 return 0;
2241}
2242
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002243static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2244{
2245 struct alc_spec *spec = codec->spec;
2246
2247 if (spec->unsol_event)
2248 spec->unsol_event(codec, res);
2249}
2250
Takashi Iwaicb53c622007-08-10 17:21:45 +02002251#ifdef CONFIG_SND_HDA_POWER_SAVE
2252static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2253{
2254 struct alc_spec *spec = codec->spec;
2255 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2256}
2257#endif
2258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259/*
2260 * Analog playback callbacks
2261 */
2262static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2263 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002264 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265{
2266 struct alc_spec *spec = codec->spec;
2267 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
2268}
2269
2270static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2271 struct hda_codec *codec,
2272 unsigned int stream_tag,
2273 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002274 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275{
2276 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002277 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2278 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279}
2280
2281static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2282 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002283 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
2285 struct alc_spec *spec = codec->spec;
2286 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2287}
2288
2289/*
2290 * Digital out
2291 */
2292static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2293 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002294 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295{
2296 struct alc_spec *spec = codec->spec;
2297 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2298}
2299
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002300static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2301 struct hda_codec *codec,
2302 unsigned int stream_tag,
2303 unsigned int format,
2304 struct snd_pcm_substream *substream)
2305{
2306 struct alc_spec *spec = codec->spec;
2307 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2308 stream_tag, format, substream);
2309}
2310
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2312 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002313 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314{
2315 struct alc_spec *spec = codec->spec;
2316 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2317}
2318
2319/*
2320 * Analog capture
2321 */
2322static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2323 struct hda_codec *codec,
2324 unsigned int stream_tag,
2325 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002326 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327{
2328 struct alc_spec *spec = codec->spec;
2329
2330 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
2331 stream_tag, 0, format);
2332 return 0;
2333}
2334
2335static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2336 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002337 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338{
2339 struct alc_spec *spec = codec->spec;
2340
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002341 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
2342 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 return 0;
2344}
2345
2346
2347/*
2348 */
2349static struct hda_pcm_stream alc880_pcm_analog_playback = {
2350 .substreams = 1,
2351 .channels_min = 2,
2352 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002353 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 .ops = {
2355 .open = alc880_playback_pcm_open,
2356 .prepare = alc880_playback_pcm_prepare,
2357 .cleanup = alc880_playback_pcm_cleanup
2358 },
2359};
2360
2361static struct hda_pcm_stream alc880_pcm_analog_capture = {
2362 .substreams = 2,
2363 .channels_min = 2,
2364 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002365 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 .ops = {
2367 .prepare = alc880_capture_pcm_prepare,
2368 .cleanup = alc880_capture_pcm_cleanup
2369 },
2370};
2371
2372static struct hda_pcm_stream alc880_pcm_digital_playback = {
2373 .substreams = 1,
2374 .channels_min = 2,
2375 .channels_max = 2,
2376 /* NID is set in alc_build_pcms */
2377 .ops = {
2378 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002379 .close = alc880_dig_playback_pcm_close,
2380 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 },
2382};
2383
2384static struct hda_pcm_stream alc880_pcm_digital_capture = {
2385 .substreams = 1,
2386 .channels_min = 2,
2387 .channels_max = 2,
2388 /* NID is set in alc_build_pcms */
2389};
2390
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002391/* Used by alc_build_pcms to flag that a PCM has no playback stream */
2392static struct hda_pcm_stream alc_pcm_null_playback = {
2393 .substreams = 0,
2394 .channels_min = 0,
2395 .channels_max = 0,
2396};
2397
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398static int alc_build_pcms(struct hda_codec *codec)
2399{
2400 struct alc_spec *spec = codec->spec;
2401 struct hda_pcm *info = spec->pcm_rec;
2402 int i;
2403
2404 codec->num_pcms = 1;
2405 codec->pcm_info = info;
2406
2407 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002408 if (spec->stream_analog_playback) {
2409 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2410 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2411 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2412 }
2413 if (spec->stream_analog_capture) {
2414 snd_assert(spec->adc_nids, return -EINVAL);
2415 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2416 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Takashi Iwai4a471b72005-12-07 13:56:29 +01002419 if (spec->channel_mode) {
2420 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2421 for (i = 0; i < spec->num_channel_mode; i++) {
2422 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2423 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 }
2426 }
2427
Takashi Iwaie08a0072006-09-07 17:52:14 +02002428 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002430 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002431 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 info->name = spec->stream_name_digital;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002433 if (spec->multiout.dig_out_nid &&
2434 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2436 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2437 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002438 if (spec->dig_in_nid &&
2439 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2441 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2442 }
2443 }
2444
Takashi Iwaie08a0072006-09-07 17:52:14 +02002445 /* If the use of more than one ADC is requested for the current
2446 * model, configure a second analog capture-only PCM.
2447 */
2448 /* Additional Analaog capture for index #2 */
2449 if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
2450 spec->adc_nids) {
2451 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002452 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002453 info->name = spec->stream_name_analog;
2454 /* No playback stream for second PCM */
2455 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
2456 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2457 if (spec->stream_analog_capture) {
2458 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2459 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
2460 }
2461 }
2462
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 return 0;
2464}
2465
2466static void alc_free(struct hda_codec *codec)
2467{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002468 struct alc_spec *spec = codec->spec;
2469 unsigned int i;
2470
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002471 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002472 return;
2473
2474 if (spec->kctl_alloc) {
2475 for (i = 0; i < spec->num_kctl_used; i++)
2476 kfree(spec->kctl_alloc[i].name);
2477 kfree(spec->kctl_alloc);
2478 }
2479 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480}
2481
2482/*
2483 */
2484static struct hda_codec_ops alc_patch_ops = {
2485 .build_controls = alc_build_controls,
2486 .build_pcms = alc_build_pcms,
2487 .init = alc_init,
2488 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002489 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002490#ifdef CONFIG_SND_HDA_POWER_SAVE
2491 .check_power_status = alc_check_power_status,
2492#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493};
2494
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002495
2496/*
2497 * Test configuration for debugging
2498 *
2499 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2500 * enum controls.
2501 */
2502#ifdef CONFIG_SND_DEBUG
2503static hda_nid_t alc880_test_dac_nids[4] = {
2504 0x02, 0x03, 0x04, 0x05
2505};
2506
2507static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002508 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002509 .items = {
2510 { "In-1", 0x0 },
2511 { "In-2", 0x1 },
2512 { "In-3", 0x2 },
2513 { "In-4", 0x3 },
2514 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002515 { "Front", 0x5 },
2516 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002517 },
2518};
2519
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002520static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002521 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002522 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002523 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002524 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002525};
2526
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002527static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2528 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002529{
2530 static char *texts[] = {
2531 "N/A", "Line Out", "HP Out",
2532 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2533 };
2534 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2535 uinfo->count = 1;
2536 uinfo->value.enumerated.items = 8;
2537 if (uinfo->value.enumerated.item >= 8)
2538 uinfo->value.enumerated.item = 7;
2539 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2540 return 0;
2541}
2542
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002543static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2544 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002545{
2546 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2547 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2548 unsigned int pin_ctl, item = 0;
2549
2550 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2551 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2552 if (pin_ctl & AC_PINCTL_OUT_EN) {
2553 if (pin_ctl & AC_PINCTL_HP_EN)
2554 item = 2;
2555 else
2556 item = 1;
2557 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2558 switch (pin_ctl & AC_PINCTL_VREFEN) {
2559 case AC_PINCTL_VREF_HIZ: item = 3; break;
2560 case AC_PINCTL_VREF_50: item = 4; break;
2561 case AC_PINCTL_VREF_GRD: item = 5; break;
2562 case AC_PINCTL_VREF_80: item = 6; break;
2563 case AC_PINCTL_VREF_100: item = 7; break;
2564 }
2565 }
2566 ucontrol->value.enumerated.item[0] = item;
2567 return 0;
2568}
2569
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002570static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2571 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002572{
2573 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2574 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2575 static unsigned int ctls[] = {
2576 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2577 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2578 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2579 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2580 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2581 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2582 };
2583 unsigned int old_ctl, new_ctl;
2584
2585 old_ctl = snd_hda_codec_read(codec, nid, 0,
2586 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2587 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2588 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002589 int val;
2590 snd_hda_codec_write_cache(codec, nid, 0,
2591 AC_VERB_SET_PIN_WIDGET_CONTROL,
2592 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002593 val = ucontrol->value.enumerated.item[0] >= 3 ?
2594 HDA_AMP_MUTE : 0;
2595 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2596 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002597 return 1;
2598 }
2599 return 0;
2600}
2601
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002602static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2603 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002604{
2605 static char *texts[] = {
2606 "Front", "Surround", "CLFE", "Side"
2607 };
2608 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2609 uinfo->count = 1;
2610 uinfo->value.enumerated.items = 4;
2611 if (uinfo->value.enumerated.item >= 4)
2612 uinfo->value.enumerated.item = 3;
2613 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2614 return 0;
2615}
2616
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002617static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2618 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002619{
2620 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2621 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2622 unsigned int sel;
2623
2624 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2625 ucontrol->value.enumerated.item[0] = sel & 3;
2626 return 0;
2627}
2628
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002629static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2630 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002631{
2632 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2633 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2634 unsigned int sel;
2635
2636 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2637 if (ucontrol->value.enumerated.item[0] != sel) {
2638 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002639 snd_hda_codec_write_cache(codec, nid, 0,
2640 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002641 return 1;
2642 }
2643 return 0;
2644}
2645
2646#define PIN_CTL_TEST(xname,nid) { \
2647 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2648 .name = xname, \
2649 .info = alc_test_pin_ctl_info, \
2650 .get = alc_test_pin_ctl_get, \
2651 .put = alc_test_pin_ctl_put, \
2652 .private_value = nid \
2653 }
2654
2655#define PIN_SRC_TEST(xname,nid) { \
2656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2657 .name = xname, \
2658 .info = alc_test_pin_src_info, \
2659 .get = alc_test_pin_src_get, \
2660 .put = alc_test_pin_src_put, \
2661 .private_value = nid \
2662 }
2663
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002664static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002665 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2666 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2667 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2668 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002669 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2670 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2671 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2672 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002673 PIN_CTL_TEST("Front Pin Mode", 0x14),
2674 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2675 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2676 PIN_CTL_TEST("Side Pin Mode", 0x17),
2677 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2678 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2679 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2680 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2681 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2682 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2683 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2684 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2685 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2686 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2687 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2688 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2689 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2690 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2691 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2692 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2693 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2694 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002695 {
2696 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2697 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002698 .info = alc_ch_mode_info,
2699 .get = alc_ch_mode_get,
2700 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002701 },
2702 { } /* end */
2703};
2704
2705static struct hda_verb alc880_test_init_verbs[] = {
2706 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002707 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2708 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2709 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2710 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2711 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2712 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2713 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2714 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002715 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002716 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2717 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2718 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2719 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002720 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002721 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2722 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2723 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2724 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002725 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002726 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2727 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2728 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2729 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002730 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002731 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2732 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002733 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2734 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2735 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002736 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002737 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2738 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2739 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2740 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002741 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002742 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002743 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002744 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002745 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002746 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002747 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002748 /* Analog input/passthru */
2749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2751 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2752 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2753 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002754 { }
2755};
2756#endif
2757
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758/*
2759 */
2760
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002761static const char *alc880_models[ALC880_MODEL_LAST] = {
2762 [ALC880_3ST] = "3stack",
2763 [ALC880_TCL_S700] = "tcl",
2764 [ALC880_3ST_DIG] = "3stack-digout",
2765 [ALC880_CLEVO] = "clevo",
2766 [ALC880_5ST] = "5stack",
2767 [ALC880_5ST_DIG] = "5stack-digout",
2768 [ALC880_W810] = "w810",
2769 [ALC880_Z71V] = "z71v",
2770 [ALC880_6ST] = "6stack",
2771 [ALC880_6ST_DIG] = "6stack-digout",
2772 [ALC880_ASUS] = "asus",
2773 [ALC880_ASUS_W1V] = "asus-w1v",
2774 [ALC880_ASUS_DIG] = "asus-dig",
2775 [ALC880_ASUS_DIG2] = "asus-dig2",
2776 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002777 [ALC880_UNIWILL_P53] = "uniwill-p53",
2778 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002779 [ALC880_F1734] = "F1734",
2780 [ALC880_LG] = "lg",
2781 [ALC880_LG_LW] = "lg-lw",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002782#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002783 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002784#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002785 [ALC880_AUTO] = "auto",
2786};
2787
2788static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002789 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002790 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2791 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2792 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2793 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2794 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2795 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2796 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2797 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002798 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2799 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002800 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2801 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2802 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2803 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2804 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2805 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2806 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2807 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2808 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2809 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Tobin Davis0e4ceb72007-01-08 10:54:26 +01002810 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002811 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2812 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2813 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002814 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002815 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002816 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2817 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002818 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2819 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002820 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2821 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2822 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2823 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002824 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2825 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002826 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002827 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002828 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002829 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002830 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2831 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002832 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2833 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002834 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002835 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002836 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002837 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002838 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002839 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2840 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002841 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002842 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2843 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
2844 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2845 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002846 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2847 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002848 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002849 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002850 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2851 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002852 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2853 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2854 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002855 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
2856 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2857 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 {}
2859};
2860
Takashi Iwai16ded522005-06-10 19:58:24 +02002861/*
Kailang Yangdf694da2005-12-05 19:42:22 +01002862 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02002863 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002864static struct alc_config_preset alc880_presets[] = {
2865 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002866 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002867 .init_verbs = { alc880_volume_init_verbs,
2868 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002869 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002870 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002871 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2872 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002873 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002874 .input_mux = &alc880_capture_source,
2875 },
2876 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002877 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002878 .init_verbs = { alc880_volume_init_verbs,
2879 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002880 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002881 .dac_nids = alc880_dac_nids,
2882 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002883 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2884 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002885 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002886 .input_mux = &alc880_capture_source,
2887 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002888 [ALC880_TCL_S700] = {
2889 .mixers = { alc880_tcl_s700_mixer },
2890 .init_verbs = { alc880_volume_init_verbs,
2891 alc880_pin_tcl_S700_init_verbs,
2892 alc880_gpio2_init_verbs },
2893 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2894 .dac_nids = alc880_dac_nids,
2895 .hp_nid = 0x03,
2896 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2897 .channel_mode = alc880_2_jack_modes,
2898 .input_mux = &alc880_capture_source,
2899 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002900 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002901 .mixers = { alc880_three_stack_mixer,
2902 alc880_five_stack_mixer},
2903 .init_verbs = { alc880_volume_init_verbs,
2904 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002905 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2906 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002907 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
2908 .channel_mode = alc880_fivestack_modes,
2909 .input_mux = &alc880_capture_source,
2910 },
2911 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002912 .mixers = { alc880_three_stack_mixer,
2913 alc880_five_stack_mixer },
2914 .init_verbs = { alc880_volume_init_verbs,
2915 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002916 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2917 .dac_nids = alc880_dac_nids,
2918 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002919 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
2920 .channel_mode = alc880_fivestack_modes,
2921 .input_mux = &alc880_capture_source,
2922 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02002923 [ALC880_6ST] = {
2924 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002925 .init_verbs = { alc880_volume_init_verbs,
2926 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02002927 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
2928 .dac_nids = alc880_6st_dac_nids,
2929 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
2930 .channel_mode = alc880_sixstack_modes,
2931 .input_mux = &alc880_6stack_capture_source,
2932 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002933 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002934 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002935 .init_verbs = { alc880_volume_init_verbs,
2936 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002937 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
2938 .dac_nids = alc880_6st_dac_nids,
2939 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002940 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
2941 .channel_mode = alc880_sixstack_modes,
2942 .input_mux = &alc880_6stack_capture_source,
2943 },
2944 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002945 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002946 .init_verbs = { alc880_volume_init_verbs,
2947 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02002948 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002949 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
2950 .dac_nids = alc880_w810_dac_nids,
2951 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002952 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
2953 .channel_mode = alc880_w810_modes,
2954 .input_mux = &alc880_capture_source,
2955 },
2956 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002957 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002958 .init_verbs = { alc880_volume_init_verbs,
2959 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002960 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
2961 .dac_nids = alc880_z71v_dac_nids,
2962 .dig_out_nid = ALC880_DIGOUT_NID,
2963 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002964 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2965 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002966 .input_mux = &alc880_capture_source,
2967 },
2968 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002969 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002970 .init_verbs = { alc880_volume_init_verbs,
2971 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002972 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
2973 .dac_nids = alc880_f1734_dac_nids,
2974 .hp_nid = 0x02,
2975 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2976 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002977 .input_mux = &alc880_capture_source,
2978 },
2979 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002980 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002981 .init_verbs = { alc880_volume_init_verbs,
2982 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002983 alc880_gpio1_init_verbs },
2984 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2985 .dac_nids = alc880_asus_dac_nids,
2986 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
2987 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002988 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002989 .input_mux = &alc880_capture_source,
2990 },
2991 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002992 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002993 .init_verbs = { alc880_volume_init_verbs,
2994 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002995 alc880_gpio1_init_verbs },
2996 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2997 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002998 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002999 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3000 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003001 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003002 .input_mux = &alc880_capture_source,
3003 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003004 [ALC880_ASUS_DIG2] = {
3005 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003006 .init_verbs = { alc880_volume_init_verbs,
3007 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003008 alc880_gpio2_init_verbs }, /* use GPIO2 */
3009 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3010 .dac_nids = alc880_asus_dac_nids,
3011 .dig_out_nid = ALC880_DIGOUT_NID,
3012 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3013 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003014 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003015 .input_mux = &alc880_capture_source,
3016 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003017 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003018 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003019 .init_verbs = { alc880_volume_init_verbs,
3020 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003021 alc880_gpio1_init_verbs },
3022 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3023 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003024 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003025 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3026 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003027 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003028 .input_mux = &alc880_capture_source,
3029 },
3030 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003031 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003032 .init_verbs = { alc880_volume_init_verbs,
3033 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003034 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3035 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003036 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003037 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3038 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003039 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003040 .input_mux = &alc880_capture_source,
3041 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003042 [ALC880_UNIWILL] = {
3043 .mixers = { alc880_uniwill_mixer },
3044 .init_verbs = { alc880_volume_init_verbs,
3045 alc880_uniwill_init_verbs },
3046 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3047 .dac_nids = alc880_asus_dac_nids,
3048 .dig_out_nid = ALC880_DIGOUT_NID,
3049 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3050 .channel_mode = alc880_threestack_modes,
3051 .need_dac_fix = 1,
3052 .input_mux = &alc880_capture_source,
3053 .unsol_event = alc880_uniwill_unsol_event,
3054 .init_hook = alc880_uniwill_automute,
3055 },
3056 [ALC880_UNIWILL_P53] = {
3057 .mixers = { alc880_uniwill_p53_mixer },
3058 .init_verbs = { alc880_volume_init_verbs,
3059 alc880_uniwill_p53_init_verbs },
3060 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3061 .dac_nids = alc880_asus_dac_nids,
3062 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003063 .channel_mode = alc880_threestack_modes,
3064 .input_mux = &alc880_capture_source,
3065 .unsol_event = alc880_uniwill_p53_unsol_event,
3066 .init_hook = alc880_uniwill_p53_hp_automute,
3067 },
3068 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003069 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003070 alc880_pcbeep_mixer, },
3071 .init_verbs = { alc880_volume_init_verbs,
3072 alc880_uniwill_p53_init_verbs,
3073 alc880_beep_init_verbs },
3074 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3075 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003076 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003077 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3078 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003079 .input_mux = &alc880_capture_source,
3080 .unsol_event = alc880_uniwill_p53_unsol_event,
3081 .init_hook = alc880_uniwill_p53_hp_automute,
3082 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003083 [ALC880_CLEVO] = {
3084 .mixers = { alc880_three_stack_mixer },
3085 .init_verbs = { alc880_volume_init_verbs,
3086 alc880_pin_clevo_init_verbs },
3087 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3088 .dac_nids = alc880_dac_nids,
3089 .hp_nid = 0x03,
3090 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3091 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003092 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003093 .input_mux = &alc880_capture_source,
3094 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003095 [ALC880_LG] = {
3096 .mixers = { alc880_lg_mixer },
3097 .init_verbs = { alc880_volume_init_verbs,
3098 alc880_lg_init_verbs },
3099 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3100 .dac_nids = alc880_lg_dac_nids,
3101 .dig_out_nid = ALC880_DIGOUT_NID,
3102 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3103 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003104 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003105 .input_mux = &alc880_lg_capture_source,
3106 .unsol_event = alc880_lg_unsol_event,
3107 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003108#ifdef CONFIG_SND_HDA_POWER_SAVE
3109 .loopbacks = alc880_lg_loopbacks,
3110#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003111 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003112 [ALC880_LG_LW] = {
3113 .mixers = { alc880_lg_lw_mixer },
3114 .init_verbs = { alc880_volume_init_verbs,
3115 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003116 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003117 .dac_nids = alc880_dac_nids,
3118 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003119 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3120 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003121 .input_mux = &alc880_lg_lw_capture_source,
3122 .unsol_event = alc880_lg_lw_unsol_event,
3123 .init_hook = alc880_lg_lw_automute,
3124 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003125#ifdef CONFIG_SND_DEBUG
3126 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003127 .mixers = { alc880_test_mixer },
3128 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3130 .dac_nids = alc880_test_dac_nids,
3131 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003132 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3133 .channel_mode = alc880_test_modes,
3134 .input_mux = &alc880_test_capture_source,
3135 },
3136#endif
3137};
3138
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003139/*
3140 * Automatic parse of I/O pins from the BIOS configuration
3141 */
3142
3143#define NUM_CONTROL_ALLOC 32
3144#define NUM_VERB_ALLOC 32
3145
3146enum {
3147 ALC_CTL_WIDGET_VOL,
3148 ALC_CTL_WIDGET_MUTE,
3149 ALC_CTL_BIND_MUTE,
3150};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003151static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003152 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3153 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003154 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003155};
3156
3157/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003158static int add_control(struct alc_spec *spec, int type, const char *name,
3159 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003160{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003161 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003162
3163 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3164 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3165
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003166 /* array + terminator */
3167 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3168 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003169 return -ENOMEM;
3170 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003171 memcpy(knew, spec->kctl_alloc,
3172 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003173 kfree(spec->kctl_alloc);
3174 }
3175 spec->kctl_alloc = knew;
3176 spec->num_kctl_alloc = num;
3177 }
3178
3179 knew = &spec->kctl_alloc[spec->num_kctl_used];
3180 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003181 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003182 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003183 return -ENOMEM;
3184 knew->private_value = val;
3185 spec->num_kctl_used++;
3186 return 0;
3187}
3188
3189#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3190#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3191#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3192#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3193#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3194#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3195#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3196#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3197#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3198#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3199#define ALC880_PIN_CD_NID 0x1c
3200
3201/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003202static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3203 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003204{
3205 hda_nid_t nid;
3206 int assigned[4];
3207 int i, j;
3208
3209 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003210 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003211
3212 /* check the pins hardwired to audio widget */
3213 for (i = 0; i < cfg->line_outs; i++) {
3214 nid = cfg->line_out_pins[i];
3215 if (alc880_is_fixed_pin(nid)) {
3216 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003217 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003218 assigned[idx] = 1;
3219 }
3220 }
3221 /* left pins can be connect to any audio widget */
3222 for (i = 0; i < cfg->line_outs; i++) {
3223 nid = cfg->line_out_pins[i];
3224 if (alc880_is_fixed_pin(nid))
3225 continue;
3226 /* search for an empty channel */
3227 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003228 if (!assigned[j]) {
3229 spec->multiout.dac_nids[i] =
3230 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003231 assigned[j] = 1;
3232 break;
3233 }
3234 }
3235 }
3236 spec->multiout.num_dacs = cfg->line_outs;
3237 return 0;
3238}
3239
3240/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003241static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3242 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003243{
3244 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003245 static const char *chname[4] = {
3246 "Front", "Surround", NULL /*CLFE*/, "Side"
3247 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003248 hda_nid_t nid;
3249 int i, err;
3250
3251 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003252 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003253 continue;
3254 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3255 if (i == 2) {
3256 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003257 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3258 "Center Playback Volume",
3259 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3260 HDA_OUTPUT));
3261 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003262 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003263 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3264 "LFE Playback Volume",
3265 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3266 HDA_OUTPUT));
3267 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003268 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003269 err = add_control(spec, ALC_CTL_BIND_MUTE,
3270 "Center Playback Switch",
3271 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3272 HDA_INPUT));
3273 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003274 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003275 err = add_control(spec, ALC_CTL_BIND_MUTE,
3276 "LFE Playback Switch",
3277 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3278 HDA_INPUT));
3279 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003280 return err;
3281 } else {
3282 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003283 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3284 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3285 HDA_OUTPUT));
3286 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003287 return err;
3288 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003289 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3290 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3291 HDA_INPUT));
3292 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003293 return err;
3294 }
3295 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003296 return 0;
3297}
3298
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003299/* add playback controls for speaker and HP outputs */
3300static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3301 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003302{
3303 hda_nid_t nid;
3304 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003305 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003306
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003307 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003308 return 0;
3309
3310 if (alc880_is_fixed_pin(pin)) {
3311 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003312 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003313 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003314 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003315 else
3316 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003317 /* control HP volume/switch on the output mixer amp */
3318 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003319 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003320 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3321 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3322 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003323 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003324 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003325 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3326 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3327 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003328 return err;
3329 } else if (alc880_is_multi_pin(pin)) {
3330 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003331 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003332 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003333 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3334 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3335 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003336 return err;
3337 }
3338 return 0;
3339}
3340
3341/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003342static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3343 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003344 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003345{
3346 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003347 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003348
3349 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003350 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3351 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3352 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003353 return err;
3354 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003355 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3356 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3357 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003358 return err;
3359 return 0;
3360}
3361
3362/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003363static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3364 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003365{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003366 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003367 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003368
3369 for (i = 0; i < AUTO_PIN_LAST; i++) {
3370 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003371 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003372 err = new_analog_input(spec, cfg->input_pins[i],
3373 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003374 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003375 if (err < 0)
3376 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003377 imux->items[imux->num_items].label =
3378 auto_pin_cfg_labels[i];
3379 imux->items[imux->num_items].index =
3380 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003381 imux->num_items++;
3382 }
3383 }
3384 return 0;
3385}
3386
Kailang Yangdf694da2005-12-05 19:42:22 +01003387static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3388 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003389 int dac_idx)
3390{
3391 /* set as output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003392 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3393 pin_type);
3394 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3395 AMP_OUT_UNMUTE);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003396 /* need the manual connection? */
3397 if (alc880_is_multi_pin(nid)) {
3398 struct alc_spec *spec = codec->spec;
3399 int idx = alc880_multi_pin_idx(nid);
3400 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3401 AC_VERB_SET_CONNECT_SEL,
3402 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3403 }
3404}
3405
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003406static int get_pin_type(int line_out_type)
3407{
3408 if (line_out_type == AUTO_PIN_HP_OUT)
3409 return PIN_HP;
3410 else
3411 return PIN_OUT;
3412}
3413
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003414static void alc880_auto_init_multi_out(struct hda_codec *codec)
3415{
3416 struct alc_spec *spec = codec->spec;
3417 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003418
3419 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003420 for (i = 0; i < spec->autocfg.line_outs; i++) {
3421 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003422 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3423 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424 }
3425}
3426
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003427static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003428{
3429 struct alc_spec *spec = codec->spec;
3430 hda_nid_t pin;
3431
Takashi Iwai82bc9552006-03-21 11:24:42 +01003432 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003433 if (pin) /* connect to front */
3434 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003435 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003436 if (pin) /* connect to front */
3437 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3438}
3439
3440static void alc880_auto_init_analog_input(struct hda_codec *codec)
3441{
3442 struct alc_spec *spec = codec->spec;
3443 int i;
3444
3445 for (i = 0; i < AUTO_PIN_LAST; i++) {
3446 hda_nid_t nid = spec->autocfg.input_pins[i];
3447 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003448 snd_hda_codec_write(codec, nid, 0,
3449 AC_VERB_SET_PIN_WIDGET_CONTROL,
3450 i <= AUTO_PIN_FRONT_MIC ?
3451 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003452 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003453 snd_hda_codec_write(codec, nid, 0,
3454 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003455 AMP_OUT_MUTE);
3456 }
3457 }
3458}
3459
3460/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003461/* return 1 if successful, 0 if the proper config is not found,
3462 * or a negative error code
3463 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003464static int alc880_parse_auto_config(struct hda_codec *codec)
3465{
3466 struct alc_spec *spec = codec->spec;
3467 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003468 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003469
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003470 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3471 alc880_ignore);
3472 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003473 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003474 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003475 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003476
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003477 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3478 if (err < 0)
3479 return err;
3480 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3481 if (err < 0)
3482 return err;
3483 err = alc880_auto_create_extra_out(spec,
3484 spec->autocfg.speaker_pins[0],
3485 "Speaker");
3486 if (err < 0)
3487 return err;
3488 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3489 "Headphone");
3490 if (err < 0)
3491 return err;
3492 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3493 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003494 return err;
3495
3496 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3497
3498 if (spec->autocfg.dig_out_pin)
3499 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3500 if (spec->autocfg.dig_in_pin)
3501 spec->dig_in_nid = ALC880_DIGIN_NID;
3502
3503 if (spec->kctl_alloc)
3504 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3505
3506 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3507
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003508 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003509 spec->input_mux = &spec->private_imux;
3510
3511 return 1;
3512}
3513
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003514/* additional initialization for auto-configuration model */
3515static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003516{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003517 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003518 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003519 alc880_auto_init_analog_input(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003520}
3521
3522/*
3523 * OK, here we have finally the patch for ALC880
3524 */
3525
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526static int patch_alc880(struct hda_codec *codec)
3527{
3528 struct alc_spec *spec;
3529 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003530 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003532 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 if (spec == NULL)
3534 return -ENOMEM;
3535
3536 codec->spec = spec;
3537
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003538 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3539 alc880_models,
3540 alc880_cfg_tbl);
3541 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003542 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3543 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003544 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 }
3546
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003547 if (board_config == ALC880_AUTO) {
3548 /* automatic parse from the BIOS config */
3549 err = alc880_parse_auto_config(codec);
3550 if (err < 0) {
3551 alc_free(codec);
3552 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003553 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003554 printk(KERN_INFO
3555 "hda_codec: Cannot set up configuration "
3556 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003557 board_config = ALC880_3ST;
3558 }
3559 }
3560
Kailang Yangdf694da2005-12-05 19:42:22 +01003561 if (board_config != ALC880_AUTO)
3562 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
3564 spec->stream_name_analog = "ALC880 Analog";
3565 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3566 spec->stream_analog_capture = &alc880_pcm_analog_capture;
3567
3568 spec->stream_name_digital = "ALC880 Digital";
3569 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3570 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3571
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003572 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003573 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003574 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003575 /* get type */
3576 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003577 if (wcap != AC_WID_AUD_IN) {
3578 spec->adc_nids = alc880_adc_nids_alt;
3579 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003580 spec->mixers[spec->num_mixers] =
3581 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003582 spec->num_mixers++;
3583 } else {
3584 spec->adc_nids = alc880_adc_nids;
3585 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3586 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3587 spec->num_mixers++;
3588 }
3589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
3591 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003592 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003593 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003594#ifdef CONFIG_SND_HDA_POWER_SAVE
3595 if (!spec->loopback.amplist)
3596 spec->loopback.amplist = alc880_loopbacks;
3597#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599 return 0;
3600}
3601
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003602
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603/*
3604 * ALC260 support
3605 */
3606
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003607static hda_nid_t alc260_dac_nids[1] = {
3608 /* front */
3609 0x02,
3610};
3611
3612static hda_nid_t alc260_adc_nids[1] = {
3613 /* ADC0 */
3614 0x04,
3615};
3616
Kailang Yangdf694da2005-12-05 19:42:22 +01003617static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003618 /* ADC1 */
3619 0x05,
3620};
3621
Kailang Yangdf694da2005-12-05 19:42:22 +01003622static hda_nid_t alc260_hp_adc_nids[2] = {
3623 /* ADC1, 0 */
3624 0x05, 0x04
3625};
3626
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003627/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3628 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3629 */
3630static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003631 /* ADC0, ADC1 */
3632 0x04, 0x05
3633};
3634
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003635#define ALC260_DIGOUT_NID 0x03
3636#define ALC260_DIGIN_NID 0x06
3637
3638static struct hda_input_mux alc260_capture_source = {
3639 .num_items = 4,
3640 .items = {
3641 { "Mic", 0x0 },
3642 { "Front Mic", 0x1 },
3643 { "Line", 0x2 },
3644 { "CD", 0x4 },
3645 },
3646};
3647
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003648/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003649 * headphone jack and the internal CD lines since these are the only pins at
3650 * which audio can appear. For flexibility, also allow the option of
3651 * recording the mixer output on the second ADC (ADC0 doesn't have a
3652 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003653 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003654static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3655 {
3656 .num_items = 3,
3657 .items = {
3658 { "Mic/Line", 0x0 },
3659 { "CD", 0x4 },
3660 { "Headphone", 0x2 },
3661 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003662 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003663 {
3664 .num_items = 4,
3665 .items = {
3666 { "Mic/Line", 0x0 },
3667 { "CD", 0x4 },
3668 { "Headphone", 0x2 },
3669 { "Mixer", 0x5 },
3670 },
3671 },
3672
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003673};
3674
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003675/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3676 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003677 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003678static struct hda_input_mux alc260_acer_capture_sources[2] = {
3679 {
3680 .num_items = 4,
3681 .items = {
3682 { "Mic", 0x0 },
3683 { "Line", 0x2 },
3684 { "CD", 0x4 },
3685 { "Headphone", 0x5 },
3686 },
3687 },
3688 {
3689 .num_items = 5,
3690 .items = {
3691 { "Mic", 0x0 },
3692 { "Line", 0x2 },
3693 { "CD", 0x4 },
3694 { "Headphone", 0x6 },
3695 { "Mixer", 0x5 },
3696 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003697 },
3698};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699/*
3700 * This is just place-holder, so there's something for alc_build_pcms to look
3701 * at when it calculates the maximum number of channels. ALC260 has no mixer
3702 * element which allows changing the channel mode, so the verb list is
3703 * never used.
3704 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003705static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 { 2, NULL },
3707};
3708
Kailang Yangdf694da2005-12-05 19:42:22 +01003709
3710/* Mixer combinations
3711 *
3712 * basic: base_output + input + pc_beep + capture
3713 * HP: base_output + input + capture_alt
3714 * HP_3013: hp_3013 + input + capture
3715 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003716 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003717 */
3718
3719static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003720 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003721 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003722 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3723 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3724 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3725 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3726 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003727};
Kailang Yangdf694da2005-12-05 19:42:22 +01003728
3729static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3731 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3732 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3733 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3734 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3735 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3736 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3737 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 { } /* end */
3739};
3740
Kailang Yangdf694da2005-12-05 19:42:22 +01003741static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3742 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3743 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3744 { } /* end */
3745};
3746
3747static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
3748 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3749 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3750 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
3751 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
3752 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3753 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
3754 HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3755 HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003756 { } /* end */
3757};
3758
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003759/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
3760 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
3761 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003762static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003763 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003764 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003765 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003766 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3767 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3768 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
3769 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003770 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003771 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3772 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3773 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003774 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003775 { } /* end */
3776};
3777
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003778/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
3779 * versions of the ALC260 don't act on requests to enable mic bias from NID
3780 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
3781 * datasheet doesn't mention this restriction. At this stage it's not clear
3782 * whether this behaviour is intentional or is a hardware bug in chip
3783 * revisions available in early 2006. Therefore for now allow the
3784 * "Headphone Jack Mode" control to span all choices, but if it turns out
3785 * that the lack of mic bias for this NID is intentional we could change the
3786 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
3787 *
3788 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
3789 * don't appear to make the mic bias available from the "line" jack, even
3790 * though the NID used for this jack (0x14) can supply it. The theory is
3791 * that perhaps Acer have included blocking capacitors between the ALC260
3792 * and the output jack. If this turns out to be the case for all such
3793 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
3794 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01003795 *
3796 * The C20x Tablet series have a mono internal speaker which is controlled
3797 * via the chip's Mono sum widget and pin complex, so include the necessary
3798 * controls for such models. On models without a "mono speaker" the control
3799 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003800 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003801static struct snd_kcontrol_new alc260_acer_mixer[] = {
3802 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3803 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003804 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Jonathan Woithebd869482006-11-28 11:35:52 +01003805 HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
3806 HDA_OUTPUT),
3807 HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
3808 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003809 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3810 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3811 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3812 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3813 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3814 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3815 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3816 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3817 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3818 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3819 { } /* end */
3820};
3821
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003822/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
3823 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
3824 */
3825static struct snd_kcontrol_new alc260_will_mixer[] = {
3826 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3827 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
3828 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3829 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3830 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3831 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3832 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3833 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3834 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3835 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3836 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3837 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3838 { } /* end */
3839};
3840
3841/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
3842 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
3843 */
3844static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
3845 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3846 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, 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 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3850 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
3851 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
3852 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3853 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3854 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3855 { } /* end */
3856};
3857
Kailang Yangdf694da2005-12-05 19:42:22 +01003858/* capture mixer elements */
3859static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003860 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
3861 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003862 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
3863 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003864 {
3865 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01003866 /* The multiple "Capture Source" controls confuse alsamixer
3867 * So call somewhat different..
3868 * FIXME: the controls appear in the "playback" view!
3869 */
3870 /* .name = "Capture Source", */
3871 .name = "Input Source",
3872 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003873 .info = alc_mux_enum_info,
3874 .get = alc_mux_enum_get,
3875 .put = alc_mux_enum_put,
3876 },
3877 { } /* end */
3878};
3879
Kailang Yangdf694da2005-12-05 19:42:22 +01003880static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
3881 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
3882 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
3883 {
3884 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3885 /* The multiple "Capture Source" controls confuse alsamixer
3886 * So call somewhat different..
3887 * FIXME: the controls appear in the "playback" view!
3888 */
3889 /* .name = "Capture Source", */
3890 .name = "Input Source",
3891 .count = 1,
3892 .info = alc_mux_enum_info,
3893 .get = alc_mux_enum_get,
3894 .put = alc_mux_enum_put,
3895 },
3896 { } /* end */
3897};
3898
3899/*
3900 * initialization verbs
3901 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902static struct hda_verb alc260_init_verbs[] = {
3903 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02003904 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02003906 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003908 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003910 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02003912 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01003914 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02003916 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02003918 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02003920 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3921 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02003922 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 /* set connection select to line in (default select for this ADC) */
3924 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02003925 /* mute capture amp left and right */
3926 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3927 /* set connection select to line in (default select for this ADC) */
3928 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02003929 /* set vol=0 Line-Out mixer amp left and right */
3930 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3931 /* unmute pin widget amp left and right (no gain on this amp) */
3932 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3933 /* set vol=0 HP mixer amp left and right */
3934 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3935 /* unmute pin widget amp left and right (no gain on this amp) */
3936 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3937 /* set vol=0 Mono mixer amp left and right */
3938 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3939 /* unmute pin widget amp left and right (no gain on this amp) */
3940 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3941 /* unmute LINE-2 out pin */
3942 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003943 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
3944 * Line In 2 = 0x03
3945 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003946 /* mute analog inputs */
3947 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3948 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3949 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3950 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3951 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003953 /* mute Front out path */
3954 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3955 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3956 /* mute Headphone out path */
3957 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3958 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3959 /* mute Mono out path */
3960 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3961 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 { }
3963};
3964
Takashi Iwai474167d2006-05-17 17:17:43 +02003965#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01003966static struct hda_verb alc260_hp_init_verbs[] = {
3967 /* Headphone and output */
3968 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
3969 /* mono output */
3970 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3971 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3972 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
3973 /* Mic2 (front panel) pin widget for input and vref at 80% */
3974 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
3975 /* Line In pin widget for input */
3976 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3977 /* Line-2 pin widget for output */
3978 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3979 /* CD pin widget for input */
3980 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3981 /* unmute amp left and right */
3982 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
3983 /* set connection select to line in (default select for this ADC) */
3984 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
3985 /* unmute Line-Out mixer amp left and right (volume = 0) */
3986 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
3987 /* mute pin widget amp left and right (no gain on this amp) */
3988 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
3989 /* unmute HP mixer amp left and right (volume = 0) */
3990 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
3991 /* mute pin widget amp left and right (no gain on this amp) */
3992 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003993 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
3994 * Line In 2 = 0x03
3995 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003996 /* mute analog inputs */
3997 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3998 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3999 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4000 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4001 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004002 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4003 /* Unmute Front out path */
4004 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4005 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4006 /* Unmute Headphone out path */
4007 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4008 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4009 /* Unmute Mono out path */
4010 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4011 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4012 { }
4013};
Takashi Iwai474167d2006-05-17 17:17:43 +02004014#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004015
4016static struct hda_verb alc260_hp_3013_init_verbs[] = {
4017 /* Line out and output */
4018 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4019 /* mono output */
4020 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4021 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4022 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4023 /* Mic2 (front panel) pin widget for input and vref at 80% */
4024 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4025 /* Line In pin widget for input */
4026 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4027 /* Headphone pin widget for output */
4028 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4029 /* CD pin widget for input */
4030 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4031 /* unmute amp left and right */
4032 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4033 /* set connection select to line in (default select for this ADC) */
4034 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4035 /* unmute Line-Out mixer amp left and right (volume = 0) */
4036 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4037 /* mute pin widget amp left and right (no gain on this amp) */
4038 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4039 /* unmute HP mixer amp left and right (volume = 0) */
4040 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4041 /* mute pin widget amp left and right (no gain on this amp) */
4042 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004043 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4044 * Line In 2 = 0x03
4045 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004046 /* mute analog inputs */
4047 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4048 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4049 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4050 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4051 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004052 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4053 /* Unmute Front out path */
4054 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4055 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4056 /* Unmute Headphone out path */
4057 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4058 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4059 /* Unmute Mono out path */
4060 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4061 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4062 { }
4063};
4064
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004065/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004066 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4067 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004068 */
4069static struct hda_verb alc260_fujitsu_init_verbs[] = {
4070 /* Disable all GPIOs */
4071 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4072 /* Internal speaker is connected to headphone pin */
4073 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4074 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4075 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004076 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4077 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4078 /* Ensure all other unused pins are disabled and muted. */
4079 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4080 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004081 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004082 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004083 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004084 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4085 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4086 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004087
Jonathan Woithef7ace402006-02-28 11:46:14 +01004088 /* Disable digital (SPDIF) pins */
4089 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4090 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004091
Jonathan Woithef7ace402006-02-28 11:46:14 +01004092 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4093 * when acting as an output.
4094 */
4095 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4096
4097 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004098 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4099 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4100 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4101 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4102 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4103 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4104 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4105 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4106 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004107
Jonathan Woithef7ace402006-02-28 11:46:14 +01004108 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4109 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4110 /* Unmute Line1 pin widget output buffer since it starts as an output.
4111 * If the pin mode is changed by the user the pin mode control will
4112 * take care of enabling the pin's input/output buffers as needed.
4113 * Therefore there's no need to enable the input buffer at this
4114 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004115 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004116 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004117 /* Unmute input buffer of pin widget used for Line-in (no equiv
4118 * mixer ctrl)
4119 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004120 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004121
Jonathan Woithef7ace402006-02-28 11:46:14 +01004122 /* Mute capture amp left and right */
4123 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4124 /* Set ADC connection select to match default mixer setting - line
4125 * in (on mic1 pin)
4126 */
4127 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004128
Jonathan Woithef7ace402006-02-28 11:46:14 +01004129 /* Do the same for the second ADC: mute capture input amp and
4130 * set ADC connection to line in (on mic1 pin)
4131 */
4132 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4133 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004134
Jonathan Woithef7ace402006-02-28 11:46:14 +01004135 /* Mute all inputs to mixer widget (even unconnected ones) */
4136 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4137 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4138 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4139 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4140 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4141 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4142 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4143 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004144
4145 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004146};
4147
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004148/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4149 * similar laptops (adapted from Fujitsu init verbs).
4150 */
4151static struct hda_verb alc260_acer_init_verbs[] = {
4152 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4153 * the headphone jack. Turn this on and rely on the standard mute
4154 * methods whenever the user wants to turn these outputs off.
4155 */
4156 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4157 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4158 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4159 /* Internal speaker/Headphone jack is connected to Line-out pin */
4160 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4161 /* Internal microphone/Mic jack is connected to Mic1 pin */
4162 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4163 /* Line In jack is connected to Line1 pin */
4164 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004165 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4166 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004167 /* Ensure all other unused pins are disabled and muted. */
4168 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4169 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004170 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4171 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4172 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4173 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4174 /* Disable digital (SPDIF) pins */
4175 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4176 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4177
4178 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4179 * bus when acting as outputs.
4180 */
4181 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4182 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4183
4184 /* Start with output sum widgets muted and their output gains at min */
4185 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4186 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4187 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4188 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4189 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4190 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4191 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4192 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4193 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4194
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004195 /* Unmute Line-out pin widget amp left and right
4196 * (no equiv mixer ctrl)
4197 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004198 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004199 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4200 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004201 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4202 * inputs. If the pin mode is changed by the user the pin mode control
4203 * will take care of enabling the pin's input/output buffers as needed.
4204 * Therefore there's no need to enable the input buffer at this
4205 * stage.
4206 */
4207 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4208 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4209
4210 /* Mute capture amp left and right */
4211 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4212 /* Set ADC connection select to match default mixer setting - mic
4213 * (on mic1 pin)
4214 */
4215 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4216
4217 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004218 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004219 */
4220 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004221 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004222
4223 /* Mute all inputs to mixer widget (even unconnected ones) */
4224 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4225 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4226 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4227 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4228 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4229 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4230 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4231 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4232
4233 { }
4234};
4235
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004236static struct hda_verb alc260_will_verbs[] = {
4237 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4238 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4239 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4240 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4241 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4242 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4243 {}
4244};
4245
4246static struct hda_verb alc260_replacer_672v_verbs[] = {
4247 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4248 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4249 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4250
4251 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4252 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4253 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4254
4255 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4256 {}
4257};
4258
4259/* toggle speaker-output according to the hp-jack state */
4260static void alc260_replacer_672v_automute(struct hda_codec *codec)
4261{
4262 unsigned int present;
4263
4264 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4265 present = snd_hda_codec_read(codec, 0x0f, 0,
4266 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4267 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004268 snd_hda_codec_write_cache(codec, 0x01, 0,
4269 AC_VERB_SET_GPIO_DATA, 1);
4270 snd_hda_codec_write_cache(codec, 0x0f, 0,
4271 AC_VERB_SET_PIN_WIDGET_CONTROL,
4272 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004273 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004274 snd_hda_codec_write_cache(codec, 0x01, 0,
4275 AC_VERB_SET_GPIO_DATA, 0);
4276 snd_hda_codec_write_cache(codec, 0x0f, 0,
4277 AC_VERB_SET_PIN_WIDGET_CONTROL,
4278 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004279 }
4280}
4281
4282static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4283 unsigned int res)
4284{
4285 if ((res >> 26) == ALC880_HP_EVENT)
4286 alc260_replacer_672v_automute(codec);
4287}
4288
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004289/* Test configuration for debugging, modelled after the ALC880 test
4290 * configuration.
4291 */
4292#ifdef CONFIG_SND_DEBUG
4293static hda_nid_t alc260_test_dac_nids[1] = {
4294 0x02,
4295};
4296static hda_nid_t alc260_test_adc_nids[2] = {
4297 0x04, 0x05,
4298};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004299/* For testing the ALC260, each input MUX needs its own definition since
4300 * the signal assignments are different. This assumes that the first ADC
4301 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004302 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004303static struct hda_input_mux alc260_test_capture_sources[2] = {
4304 {
4305 .num_items = 7,
4306 .items = {
4307 { "MIC1 pin", 0x0 },
4308 { "MIC2 pin", 0x1 },
4309 { "LINE1 pin", 0x2 },
4310 { "LINE2 pin", 0x3 },
4311 { "CD pin", 0x4 },
4312 { "LINE-OUT pin", 0x5 },
4313 { "HP-OUT pin", 0x6 },
4314 },
4315 },
4316 {
4317 .num_items = 8,
4318 .items = {
4319 { "MIC1 pin", 0x0 },
4320 { "MIC2 pin", 0x1 },
4321 { "LINE1 pin", 0x2 },
4322 { "LINE2 pin", 0x3 },
4323 { "CD pin", 0x4 },
4324 { "Mixer", 0x5 },
4325 { "LINE-OUT pin", 0x6 },
4326 { "HP-OUT pin", 0x7 },
4327 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004328 },
4329};
4330static struct snd_kcontrol_new alc260_test_mixer[] = {
4331 /* Output driver widgets */
4332 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4333 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4334 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4335 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4336 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4337 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4338
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004339 /* Modes for retasking pin widgets
4340 * Note: the ALC260 doesn't seem to act on requests to enable mic
4341 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4342 * mention this restriction. At this stage it's not clear whether
4343 * this behaviour is intentional or is a hardware bug in chip
4344 * revisions available at least up until early 2006. Therefore for
4345 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4346 * choices, but if it turns out that the lack of mic bias for these
4347 * NIDs is intentional we could change their modes from
4348 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4349 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004350 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4351 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4352 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4353 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4354 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4355 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4356
4357 /* Loopback mixer controls */
4358 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4359 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4360 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4361 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4362 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4363 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4364 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4365 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4366 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4367 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4368 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4369 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4370 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4371 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4372 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4373 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004374
4375 /* Controls for GPIO pins, assuming they are configured as outputs */
4376 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4377 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4378 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4379 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4380
Jonathan Woithe92621f12006-02-28 11:47:47 +01004381 /* Switches to allow the digital IO pins to be enabled. The datasheet
4382 * is ambigious as to which NID is which; testing on laptops which
4383 * make this output available should provide clarification.
4384 */
4385 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4386 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4387
Jonathan Woithef8225f62008-01-08 12:16:54 +01004388 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4389 * this output to turn on an external amplifier.
4390 */
4391 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4392 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4393
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004394 { } /* end */
4395};
4396static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004397 /* Enable all GPIOs as outputs with an initial value of 0 */
4398 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4399 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4400 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4401
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004402 /* Enable retasking pins as output, initially without power amp */
4403 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4404 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4405 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4406 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4407 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4408 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4409
Jonathan Woithe92621f12006-02-28 11:47:47 +01004410 /* Disable digital (SPDIF) pins initially, but users can enable
4411 * them via a mixer switch. In the case of SPDIF-out, this initverb
4412 * payload also sets the generation to 0, output to be in "consumer"
4413 * PCM format, copyright asserted, no pre-emphasis and no validity
4414 * control.
4415 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004416 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4417 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4418
Jonathan Woithef7ace402006-02-28 11:46:14 +01004419 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004420 * OUT1 sum bus when acting as an output.
4421 */
4422 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4423 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4424 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4425 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4426
4427 /* Start with output sum widgets muted and their output gains at min */
4428 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4429 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4430 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4431 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4432 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4433 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4434 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4435 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4436 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4437
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004438 /* Unmute retasking pin widget output buffers since the default
4439 * state appears to be output. As the pin mode is changed by the
4440 * user the pin mode control will take care of enabling the pin's
4441 * input/output buffers as needed.
4442 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004443 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4444 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4445 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4446 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4447 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4448 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4449 /* Also unmute the mono-out pin widget */
4450 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4451
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004452 /* Mute capture amp left and right */
4453 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004454 /* Set ADC connection select to match default mixer setting (mic1
4455 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004456 */
4457 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4458
4459 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004460 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004461 */
4462 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4463 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4464
4465 /* Mute all inputs to mixer widget (even unconnected ones) */
4466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4469 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4470 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4471 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4472 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4473 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4474
4475 { }
4476};
4477#endif
4478
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479static struct hda_pcm_stream alc260_pcm_analog_playback = {
4480 .substreams = 1,
4481 .channels_min = 2,
4482 .channels_max = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483};
4484
4485static struct hda_pcm_stream alc260_pcm_analog_capture = {
4486 .substreams = 1,
4487 .channels_min = 2,
4488 .channels_max = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489};
4490
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004491#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4492#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4493
Kailang Yangdf694da2005-12-05 19:42:22 +01004494/*
4495 * for BIOS auto-configuration
4496 */
4497
4498static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4499 const char *pfx)
4500{
4501 hda_nid_t nid_vol;
4502 unsigned long vol_val, sw_val;
4503 char name[32];
4504 int err;
4505
4506 if (nid >= 0x0f && nid < 0x11) {
4507 nid_vol = nid - 0x7;
4508 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4509 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4510 } else if (nid == 0x11) {
4511 nid_vol = nid - 0x7;
4512 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4513 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4514 } else if (nid >= 0x12 && nid <= 0x15) {
4515 nid_vol = 0x08;
4516 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4517 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4518 } else
4519 return 0; /* N/A */
4520
4521 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004522 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4523 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004524 return err;
4525 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004526 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4527 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004528 return err;
4529 return 1;
4530}
4531
4532/* add playback controls from the parsed DAC table */
4533static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4534 const struct auto_pin_cfg *cfg)
4535{
4536 hda_nid_t nid;
4537 int err;
4538
4539 spec->multiout.num_dacs = 1;
4540 spec->multiout.dac_nids = spec->private_dac_nids;
4541 spec->multiout.dac_nids[0] = 0x02;
4542
4543 nid = cfg->line_out_pins[0];
4544 if (nid) {
4545 err = alc260_add_playback_controls(spec, nid, "Front");
4546 if (err < 0)
4547 return err;
4548 }
4549
Takashi Iwai82bc9552006-03-21 11:24:42 +01004550 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004551 if (nid) {
4552 err = alc260_add_playback_controls(spec, nid, "Speaker");
4553 if (err < 0)
4554 return err;
4555 }
4556
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004557 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004558 if (nid) {
4559 err = alc260_add_playback_controls(spec, nid, "Headphone");
4560 if (err < 0)
4561 return err;
4562 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004563 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004564}
4565
4566/* create playback/capture controls for input pins */
4567static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4568 const struct auto_pin_cfg *cfg)
4569{
Kailang Yangdf694da2005-12-05 19:42:22 +01004570 struct hda_input_mux *imux = &spec->private_imux;
4571 int i, err, idx;
4572
4573 for (i = 0; i < AUTO_PIN_LAST; i++) {
4574 if (cfg->input_pins[i] >= 0x12) {
4575 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004576 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004577 auto_pin_cfg_labels[i], idx,
4578 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004579 if (err < 0)
4580 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004581 imux->items[imux->num_items].label =
4582 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004583 imux->items[imux->num_items].index = idx;
4584 imux->num_items++;
4585 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004586 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004587 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004588 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004589 auto_pin_cfg_labels[i], idx,
4590 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004591 if (err < 0)
4592 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004593 imux->items[imux->num_items].label =
4594 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004595 imux->items[imux->num_items].index = idx;
4596 imux->num_items++;
4597 }
4598 }
4599 return 0;
4600}
4601
4602static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4603 hda_nid_t nid, int pin_type,
4604 int sel_idx)
4605{
4606 /* set as output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004607 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4608 pin_type);
4609 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4610 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01004611 /* need the manual connection? */
4612 if (nid >= 0x12) {
4613 int idx = nid - 0x12;
4614 snd_hda_codec_write(codec, idx + 0x0b, 0,
4615 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004616 }
4617}
4618
4619static void alc260_auto_init_multi_out(struct hda_codec *codec)
4620{
4621 struct alc_spec *spec = codec->spec;
4622 hda_nid_t nid;
4623
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004624 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004625 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004626 if (nid) {
4627 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4628 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4629 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004630
Takashi Iwai82bc9552006-03-21 11:24:42 +01004631 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004632 if (nid)
4633 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4634
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004635 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004636 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004637 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004638}
Kailang Yangdf694da2005-12-05 19:42:22 +01004639
4640#define ALC260_PIN_CD_NID 0x16
4641static void alc260_auto_init_analog_input(struct hda_codec *codec)
4642{
4643 struct alc_spec *spec = codec->spec;
4644 int i;
4645
4646 for (i = 0; i < AUTO_PIN_LAST; i++) {
4647 hda_nid_t nid = spec->autocfg.input_pins[i];
4648 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004649 snd_hda_codec_write(codec, nid, 0,
4650 AC_VERB_SET_PIN_WIDGET_CONTROL,
4651 i <= AUTO_PIN_FRONT_MIC ?
4652 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004653 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004654 snd_hda_codec_write(codec, nid, 0,
4655 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004656 AMP_OUT_MUTE);
4657 }
4658 }
4659}
4660
4661/*
4662 * generic initialization of ADC, input mixers and output mixers
4663 */
4664static struct hda_verb alc260_volume_init_verbs[] = {
4665 /*
4666 * Unmute ADC0-1 and set the default input to mic-in
4667 */
4668 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4669 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4670 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4671 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4672
4673 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4674 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004675 * Note: PASD motherboards uses the Line In 2 as the input for
4676 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004677 */
4678 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004679 /* mute analog inputs */
4680 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4681 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4682 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4684 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004685
4686 /*
4687 * Set up output mixers (0x08 - 0x0a)
4688 */
4689 /* set vol=0 to output mixers */
4690 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4691 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4692 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4693 /* set up input amps for analog loopback */
4694 /* Amp Indices: DAC = 0, mixer = 1 */
4695 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4696 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4697 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4698 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4699 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4700 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4701
4702 { }
4703};
4704
4705static int alc260_parse_auto_config(struct hda_codec *codec)
4706{
4707 struct alc_spec *spec = codec->spec;
4708 unsigned int wcap;
4709 int err;
4710 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
4711
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004712 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4713 alc260_ignore);
4714 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004715 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004716 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
4717 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01004718 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004719 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01004720 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004721 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
4722 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004723 return err;
4724
4725 spec->multiout.max_channels = 2;
4726
4727 if (spec->autocfg.dig_out_pin)
4728 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
4729 if (spec->kctl_alloc)
4730 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4731
4732 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
4733
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004734 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01004735 spec->input_mux = &spec->private_imux;
4736
4737 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004738 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01004739 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4740 if (wcap != AC_WID_AUD_IN) {
4741 spec->adc_nids = alc260_adc_nids_alt;
4742 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
4743 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004744 } else {
4745 spec->adc_nids = alc260_adc_nids;
4746 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
4747 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004748 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004749 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01004750
4751 return 1;
4752}
4753
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004754/* additional initialization for auto-configuration model */
4755static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01004756{
Kailang Yangdf694da2005-12-05 19:42:22 +01004757 alc260_auto_init_multi_out(codec);
4758 alc260_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01004759}
4760
Takashi Iwaicb53c622007-08-10 17:21:45 +02004761#ifdef CONFIG_SND_HDA_POWER_SAVE
4762static struct hda_amp_list alc260_loopbacks[] = {
4763 { 0x07, HDA_INPUT, 0 },
4764 { 0x07, HDA_INPUT, 1 },
4765 { 0x07, HDA_INPUT, 2 },
4766 { 0x07, HDA_INPUT, 3 },
4767 { 0x07, HDA_INPUT, 4 },
4768 { } /* end */
4769};
4770#endif
4771
Kailang Yangdf694da2005-12-05 19:42:22 +01004772/*
4773 * ALC260 configurations
4774 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004775static const char *alc260_models[ALC260_MODEL_LAST] = {
4776 [ALC260_BASIC] = "basic",
4777 [ALC260_HP] = "hp",
4778 [ALC260_HP_3013] = "hp-3013",
4779 [ALC260_FUJITSU_S702X] = "fujitsu",
4780 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004781 [ALC260_WILL] = "will",
4782 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004783#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004784 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004785#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004786 [ALC260_AUTO] = "auto",
4787};
4788
4789static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01004790 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004791 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01004792 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01004793 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004794 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
4795 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
4796 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
4797 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
4798 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
4799 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
4800 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
4801 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
4802 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
4803 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
4804 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
4805 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004806 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004807 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02004808 {}
4809};
4810
Kailang Yangdf694da2005-12-05 19:42:22 +01004811static struct alc_config_preset alc260_presets[] = {
4812 [ALC260_BASIC] = {
4813 .mixers = { alc260_base_output_mixer,
4814 alc260_input_mixer,
4815 alc260_pc_beep_mixer,
4816 alc260_capture_mixer },
4817 .init_verbs = { alc260_init_verbs },
4818 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4819 .dac_nids = alc260_dac_nids,
4820 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4821 .adc_nids = alc260_adc_nids,
4822 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4823 .channel_mode = alc260_modes,
4824 .input_mux = &alc260_capture_source,
4825 },
4826 [ALC260_HP] = {
4827 .mixers = { alc260_base_output_mixer,
4828 alc260_input_mixer,
4829 alc260_capture_alt_mixer },
Takashi Iwai474167d2006-05-17 17:17:43 +02004830 .init_verbs = { alc260_init_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01004831 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4832 .dac_nids = alc260_dac_nids,
4833 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
4834 .adc_nids = alc260_hp_adc_nids,
4835 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4836 .channel_mode = alc260_modes,
4837 .input_mux = &alc260_capture_source,
4838 },
4839 [ALC260_HP_3013] = {
4840 .mixers = { alc260_hp_3013_mixer,
4841 alc260_input_mixer,
4842 alc260_capture_alt_mixer },
4843 .init_verbs = { alc260_hp_3013_init_verbs },
4844 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4845 .dac_nids = alc260_dac_nids,
4846 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
4847 .adc_nids = alc260_hp_adc_nids,
4848 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4849 .channel_mode = alc260_modes,
4850 .input_mux = &alc260_capture_source,
4851 },
4852 [ALC260_FUJITSU_S702X] = {
4853 .mixers = { alc260_fujitsu_mixer,
4854 alc260_capture_mixer },
4855 .init_verbs = { alc260_fujitsu_init_verbs },
4856 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4857 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004858 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
4859 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01004860 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4861 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004862 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
4863 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01004864 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004865 [ALC260_ACER] = {
4866 .mixers = { alc260_acer_mixer,
4867 alc260_capture_mixer },
4868 .init_verbs = { alc260_acer_init_verbs },
4869 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4870 .dac_nids = alc260_dac_nids,
4871 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
4872 .adc_nids = alc260_dual_adc_nids,
4873 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4874 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004875 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
4876 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004877 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004878 [ALC260_WILL] = {
4879 .mixers = { alc260_will_mixer,
4880 alc260_capture_mixer },
4881 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
4882 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4883 .dac_nids = alc260_dac_nids,
4884 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4885 .adc_nids = alc260_adc_nids,
4886 .dig_out_nid = ALC260_DIGOUT_NID,
4887 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4888 .channel_mode = alc260_modes,
4889 .input_mux = &alc260_capture_source,
4890 },
4891 [ALC260_REPLACER_672V] = {
4892 .mixers = { alc260_replacer_672v_mixer,
4893 alc260_capture_mixer },
4894 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
4895 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4896 .dac_nids = alc260_dac_nids,
4897 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4898 .adc_nids = alc260_adc_nids,
4899 .dig_out_nid = ALC260_DIGOUT_NID,
4900 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4901 .channel_mode = alc260_modes,
4902 .input_mux = &alc260_capture_source,
4903 .unsol_event = alc260_replacer_672v_unsol_event,
4904 .init_hook = alc260_replacer_672v_automute,
4905 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004906#ifdef CONFIG_SND_DEBUG
4907 [ALC260_TEST] = {
4908 .mixers = { alc260_test_mixer,
4909 alc260_capture_mixer },
4910 .init_verbs = { alc260_test_init_verbs },
4911 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
4912 .dac_nids = alc260_test_dac_nids,
4913 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
4914 .adc_nids = alc260_test_adc_nids,
4915 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4916 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004917 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
4918 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004919 },
4920#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004921};
4922
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923static int patch_alc260(struct hda_codec *codec)
4924{
4925 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004926 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004928 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 if (spec == NULL)
4930 return -ENOMEM;
4931
4932 codec->spec = spec;
4933
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004934 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
4935 alc260_models,
4936 alc260_cfg_tbl);
4937 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004938 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
4939 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01004940 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02004941 }
4942
Kailang Yangdf694da2005-12-05 19:42:22 +01004943 if (board_config == ALC260_AUTO) {
4944 /* automatic parse from the BIOS config */
4945 err = alc260_parse_auto_config(codec);
4946 if (err < 0) {
4947 alc_free(codec);
4948 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004949 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004950 printk(KERN_INFO
4951 "hda_codec: Cannot set up configuration "
4952 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01004953 board_config = ALC260_BASIC;
4954 }
Takashi Iwai16ded522005-06-10 19:58:24 +02004955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956
Kailang Yangdf694da2005-12-05 19:42:22 +01004957 if (board_config != ALC260_AUTO)
4958 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959
4960 spec->stream_name_analog = "ALC260 Analog";
4961 spec->stream_analog_playback = &alc260_pcm_analog_playback;
4962 spec->stream_analog_capture = &alc260_pcm_analog_capture;
4963
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004964 spec->stream_name_digital = "ALC260 Digital";
4965 spec->stream_digital_playback = &alc260_pcm_digital_playback;
4966 spec->stream_digital_capture = &alc260_pcm_digital_capture;
4967
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01004969 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004970 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004971#ifdef CONFIG_SND_HDA_POWER_SAVE
4972 if (!spec->loopback.amplist)
4973 spec->loopback.amplist = alc260_loopbacks;
4974#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975
4976 return 0;
4977}
4978
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004979
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980/*
4981 * ALC882 support
4982 *
4983 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
4984 * configuration. Each pin widget can choose any input DACs and a mixer.
4985 * Each ADC is connected from a mixer of all inputs. This makes possible
4986 * 6-channel independent captures.
4987 *
4988 * In addition, an independent DAC for the multi-playback (not used in this
4989 * driver yet).
4990 */
Kailang Yangdf694da2005-12-05 19:42:22 +01004991#define ALC882_DIGOUT_NID 0x06
4992#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004994static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 { 8, NULL }
4996};
4997
4998static hda_nid_t alc882_dac_nids[4] = {
4999 /* front, rear, clfe, rear_surr */
5000 0x02, 0x03, 0x04, 0x05
5001};
5002
Kailang Yangdf694da2005-12-05 19:42:22 +01005003/* identical with ALC880 */
5004#define alc882_adc_nids alc880_adc_nids
5005#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006
5007/* input MUX */
5008/* FIXME: should be a matrix-type input source selection */
5009
5010static struct hda_input_mux alc882_capture_source = {
5011 .num_items = 4,
5012 .items = {
5013 { "Mic", 0x0 },
5014 { "Front Mic", 0x1 },
5015 { "Line", 0x2 },
5016 { "CD", 0x4 },
5017 },
5018};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019#define alc882_mux_enum_info alc_mux_enum_info
5020#define alc882_mux_enum_get alc_mux_enum_get
5021
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005022static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5023 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024{
5025 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5026 struct alc_spec *spec = codec->spec;
5027 const struct hda_input_mux *imux = spec->input_mux;
5028 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
5029 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
5030 hda_nid_t nid = capture_mixers[adc_idx];
5031 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5032 unsigned int i, idx;
5033
5034 idx = ucontrol->value.enumerated.item[0];
5035 if (idx >= imux->num_items)
5036 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005037 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 return 0;
5039 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005040 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5041 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005042 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005043 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 }
5045 *cur_val = idx;
5046 return 1;
5047}
5048
Kailang Yangdf694da2005-12-05 19:42:22 +01005049/*
Kailang Yang272a5272007-05-14 11:00:38 +02005050 * 2ch mode
5051 */
5052static struct hda_verb alc882_3ST_ch2_init[] = {
5053 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5054 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5055 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5056 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5057 { } /* end */
5058};
5059
5060/*
5061 * 6ch mode
5062 */
5063static struct hda_verb alc882_3ST_ch6_init[] = {
5064 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5065 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5066 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5067 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5068 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5069 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5070 { } /* end */
5071};
5072
5073static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5074 { 2, alc882_3ST_ch2_init },
5075 { 6, alc882_3ST_ch6_init },
5076};
5077
5078/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005079 * 6ch mode
5080 */
5081static struct hda_verb alc882_sixstack_ch6_init[] = {
5082 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5083 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5084 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5085 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5086 { } /* end */
5087};
5088
5089/*
5090 * 8ch mode
5091 */
5092static struct hda_verb alc882_sixstack_ch8_init[] = {
5093 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5094 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5095 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5096 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5097 { } /* end */
5098};
5099
5100static struct hda_channel_mode alc882_sixstack_modes[2] = {
5101 { 6, alc882_sixstack_ch6_init },
5102 { 8, alc882_sixstack_ch8_init },
5103};
5104
Takashi Iwai87350ad2007-08-16 18:19:38 +02005105/*
5106 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5107 */
5108
5109/*
5110 * 2ch mode
5111 */
5112static struct hda_verb alc885_mbp_ch2_init[] = {
5113 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5114 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5115 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5116 { } /* end */
5117};
5118
5119/*
5120 * 6ch mode
5121 */
5122static struct hda_verb alc885_mbp_ch6_init[] = {
5123 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5124 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5125 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5126 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5127 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5128 { } /* end */
5129};
5130
5131static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5132 { 2, alc885_mbp_ch2_init },
5133 { 6, alc885_mbp_ch6_init },
5134};
5135
5136
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5138 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5139 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005140static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005141 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005142 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005143 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005144 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005145 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5146 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005147 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5148 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005149 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005150 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5152 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5153 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5154 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5155 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5156 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005157 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5159 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005160 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5162 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5163 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 { } /* end */
5165};
5166
Takashi Iwai87350ad2007-08-16 18:19:38 +02005167static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
5168 HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT),
5169 HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT),
5170 HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT),
5171 HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT),
5172 HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT),
5173 HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT),
5174 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5175 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
5176 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT),
5177 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5178 { } /* end */
5179};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005180static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5181 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5182 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5183 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5184 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5185 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5186 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5187 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5188 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5189 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5190 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5191 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5192 { } /* end */
5193};
5194
Kailang Yang272a5272007-05-14 11:00:38 +02005195static struct snd_kcontrol_new alc882_targa_mixer[] = {
5196 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5197 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5199 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5200 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5202 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5204 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005205 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005206 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5207 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005208 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005209 { } /* end */
5210};
5211
5212/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5213 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5214 */
5215static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5216 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5217 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5218 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5219 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5220 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5221 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5222 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5223 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5224 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5225 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5226 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5227 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005228 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005229 { } /* end */
5230};
5231
Takashi Iwai914759b2007-09-06 14:52:04 +02005232static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5233 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5234 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5235 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5236 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5237 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5238 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5239 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5240 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5241 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5242 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5243 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5244 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5245 { } /* end */
5246};
5247
Kailang Yangdf694da2005-12-05 19:42:22 +01005248static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5249 {
5250 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5251 .name = "Channel Mode",
5252 .info = alc_ch_mode_info,
5253 .get = alc_ch_mode_get,
5254 .put = alc_ch_mode_put,
5255 },
5256 { } /* end */
5257};
5258
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259static struct hda_verb alc882_init_verbs[] = {
5260 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005261 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005265 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5266 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5267 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005269 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5270 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5271 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005273 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5274 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5275 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005277 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005278 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005279 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005281 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005282 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005283 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005285 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005286 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005287 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005289 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005290 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005291 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005293 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005294 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005295 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5296 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005297 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005298 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5299 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005300 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005301 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5302 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5303 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5304 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5305 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005307 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
5309 /* FIXME: use matrix-type input source selection */
5310 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5311 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005312 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5313 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5314 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5315 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005317 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5318 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5319 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5320 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005322 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5323 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5324 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5325 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5326 /* ADC1: mute amp left and right */
5327 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005328 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005329 /* ADC2: mute amp left and right */
5330 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005331 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005332 /* ADC3: mute amp left and right */
5333 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005334 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335
5336 { }
5337};
5338
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005339static struct hda_verb alc882_eapd_verbs[] = {
5340 /* change to EAPD mode */
5341 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005342 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005343 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005344};
5345
Tobin Davis9102cd12006-12-15 10:02:12 +01005346/* Mac Pro test */
5347static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5348 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5349 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5350 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5351 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5352 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5353 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5354 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5355 { } /* end */
5356};
5357
5358static struct hda_verb alc882_macpro_init_verbs[] = {
5359 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5360 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5361 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5362 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5363 /* Front Pin: output 0 (0x0c) */
5364 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5365 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5366 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5367 /* Front Mic pin: input vref at 80% */
5368 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5369 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5370 /* Speaker: output */
5371 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5372 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5373 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5374 /* Headphone output (output 0 - 0x0c) */
5375 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5376 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5377 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5378
5379 /* FIXME: use matrix-type input source selection */
5380 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5381 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5382 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5383 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5384 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5385 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5386 /* Input mixer2 */
5387 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5388 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5389 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5390 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5391 /* Input mixer3 */
5392 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5393 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5394 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5395 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5396 /* ADC1: mute amp left and right */
5397 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5398 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5399 /* ADC2: mute amp left and right */
5400 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5401 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5402 /* ADC3: mute amp left and right */
5403 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5404 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5405
5406 { }
5407};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005408
Takashi Iwai87350ad2007-08-16 18:19:38 +02005409/* Macbook Pro rev3 */
5410static struct hda_verb alc885_mbp3_init_verbs[] = {
5411 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5412 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5413 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5414 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5415 /* Rear mixer */
5416 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5418 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5419 /* Front Pin: output 0 (0x0c) */
5420 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5421 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5422 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5423 /* HP Pin: output 0 (0x0d) */
5424 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5425 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5426 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5427 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5428 /* Mic (rear) pin: input vref at 80% */
5429 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5430 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5431 /* Front Mic pin: input vref at 80% */
5432 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5433 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5434 /* Line In pin: use output 1 when in LineOut mode */
5435 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5436 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5437 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5438
5439 /* FIXME: use matrix-type input source selection */
5440 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5441 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5443 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5444 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5445 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5446 /* Input mixer2 */
5447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5448 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5449 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5450 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5451 /* Input mixer3 */
5452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5453 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5454 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5455 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5456 /* ADC1: mute amp left and right */
5457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5458 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5459 /* ADC2: mute amp left and right */
5460 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5461 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5462 /* ADC3: mute amp left and right */
5463 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5464 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5465
5466 { }
5467};
5468
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005469/* iMac 24 mixer. */
5470static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5471 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5472 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5473 { } /* end */
5474};
5475
5476/* iMac 24 init verbs. */
5477static struct hda_verb alc885_imac24_init_verbs[] = {
5478 /* Internal speakers: output 0 (0x0c) */
5479 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5480 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5481 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5482 /* Internal speakers: output 0 (0x0c) */
5483 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5484 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5485 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5486 /* Headphone: output 0 (0x0c) */
5487 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5488 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5489 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5490 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5491 /* Front Mic: input vref at 80% */
5492 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5493 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5494 { }
5495};
5496
5497/* Toggle speaker-output according to the hp-jack state */
5498static void alc885_imac24_automute(struct hda_codec *codec)
5499{
5500 unsigned int present;
5501
5502 present = snd_hda_codec_read(codec, 0x14, 0,
5503 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005504 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5505 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5506 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5507 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005508}
5509
5510/* Processes unsolicited events. */
5511static void alc885_imac24_unsol_event(struct hda_codec *codec,
5512 unsigned int res)
5513{
5514 /* Headphone insertion or removal. */
5515 if ((res >> 26) == ALC880_HP_EVENT)
5516 alc885_imac24_automute(codec);
5517}
5518
Takashi Iwai87350ad2007-08-16 18:19:38 +02005519static void alc885_mbp3_automute(struct hda_codec *codec)
5520{
5521 unsigned int present;
5522
5523 present = snd_hda_codec_read(codec, 0x15, 0,
5524 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5525 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5526 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5527 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5528 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5529
5530}
5531static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5532 unsigned int res)
5533{
5534 /* Headphone insertion or removal. */
5535 if ((res >> 26) == ALC880_HP_EVENT)
5536 alc885_mbp3_automute(codec);
5537}
5538
5539
Kailang Yang272a5272007-05-14 11:00:38 +02005540static struct hda_verb alc882_targa_verbs[] = {
5541 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5542 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5543
5544 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5545 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5546
5547 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5548 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5549 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5550
5551 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5552 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5553 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5554 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5555 { } /* end */
5556};
5557
5558/* toggle speaker-output according to the hp-jack state */
5559static void alc882_targa_automute(struct hda_codec *codec)
5560{
5561 unsigned int present;
5562
5563 present = snd_hda_codec_read(codec, 0x14, 0,
5564 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005565 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5566 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005567 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5568 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005569}
5570
5571static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5572{
5573 /* Looks like the unsol event is incompatible with the standard
5574 * definition. 4bit tag is placed at 26 bit!
5575 */
5576 if (((res >> 26) == ALC880_HP_EVENT)) {
5577 alc882_targa_automute(codec);
5578 }
5579}
5580
5581static struct hda_verb alc882_asus_a7j_verbs[] = {
5582 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5583 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5584
5585 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5586 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5587 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5588
5589 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5590 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5591 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5592
5593 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5594 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5595 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5596 { } /* end */
5597};
5598
Takashi Iwai914759b2007-09-06 14:52:04 +02005599static struct hda_verb alc882_asus_a7m_verbs[] = {
5600 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5601 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5602
5603 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5604 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5605 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5606
5607 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5608 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5609 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5610
5611 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5612 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5613 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5614 { } /* end */
5615};
5616
Tobin Davis9102cd12006-12-15 10:02:12 +01005617static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5618{
5619 unsigned int gpiostate, gpiomask, gpiodir;
5620
5621 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5622 AC_VERB_GET_GPIO_DATA, 0);
5623
5624 if (!muted)
5625 gpiostate |= (1 << pin);
5626 else
5627 gpiostate &= ~(1 << pin);
5628
5629 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5630 AC_VERB_GET_GPIO_MASK, 0);
5631 gpiomask |= (1 << pin);
5632
5633 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5634 AC_VERB_GET_GPIO_DIRECTION, 0);
5635 gpiodir |= (1 << pin);
5636
5637
5638 snd_hda_codec_write(codec, codec->afg, 0,
5639 AC_VERB_SET_GPIO_MASK, gpiomask);
5640 snd_hda_codec_write(codec, codec->afg, 0,
5641 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5642
5643 msleep(1);
5644
5645 snd_hda_codec_write(codec, codec->afg, 0,
5646 AC_VERB_SET_GPIO_DATA, gpiostate);
5647}
5648
Takashi Iwai7debbe52007-08-16 15:01:03 +02005649/* set up GPIO at initialization */
5650static void alc885_macpro_init_hook(struct hda_codec *codec)
5651{
5652 alc882_gpio_mute(codec, 0, 0);
5653 alc882_gpio_mute(codec, 1, 0);
5654}
5655
5656/* set up GPIO and update auto-muting at initialization */
5657static void alc885_imac24_init_hook(struct hda_codec *codec)
5658{
5659 alc885_macpro_init_hook(codec);
5660 alc885_imac24_automute(codec);
5661}
5662
Kailang Yangdf694da2005-12-05 19:42:22 +01005663/*
5664 * generic initialization of ADC, input mixers and output mixers
5665 */
5666static struct hda_verb alc882_auto_init_verbs[] = {
5667 /*
5668 * Unmute ADC0-2 and set the default input to mic-in
5669 */
5670 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5671 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5672 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5673 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5674 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5675 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5676
Takashi Iwaicb53c622007-08-10 17:21:45 +02005677 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01005678 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005679 * Note: PASD motherboards uses the Line In 2 as the input for
5680 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005681 */
5682 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005683 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5684 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5685 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5686 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5687 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005688
5689 /*
5690 * Set up output mixers (0x0c - 0x0f)
5691 */
5692 /* set vol=0 to output mixers */
5693 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5694 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5695 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5696 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5697 /* set up input amps for analog loopback */
5698 /* Amp Indices: DAC = 0, mixer = 1 */
5699 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5700 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5701 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5702 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5703 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5704 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5705 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5706 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5707 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5708 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5709
5710 /* FIXME: use matrix-type input source selection */
5711 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5712 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5713 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5714 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5715 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5716 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5717 /* Input mixer2 */
5718 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5719 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5720 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5721 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5722 /* Input mixer3 */
5723 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5724 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5725 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5726 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5727
5728 { }
5729};
5730
5731/* capture mixer elements */
5732static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
5733 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5734 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5735 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5736 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5737 {
5738 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5739 /* The multiple "Capture Source" controls confuse alsamixer
5740 * So call somewhat different..
5741 * FIXME: the controls appear in the "playback" view!
5742 */
5743 /* .name = "Capture Source", */
5744 .name = "Input Source",
5745 .count = 2,
5746 .info = alc882_mux_enum_info,
5747 .get = alc882_mux_enum_get,
5748 .put = alc882_mux_enum_put,
5749 },
5750 { } /* end */
5751};
5752
5753static struct snd_kcontrol_new alc882_capture_mixer[] = {
5754 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
5755 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
5756 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
5757 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
5758 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
5759 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
5760 {
5761 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5762 /* The multiple "Capture Source" controls confuse alsamixer
5763 * So call somewhat different..
5764 * FIXME: the controls appear in the "playback" view!
5765 */
5766 /* .name = "Capture Source", */
5767 .name = "Input Source",
5768 .count = 3,
5769 .info = alc882_mux_enum_info,
5770 .get = alc882_mux_enum_get,
5771 .put = alc882_mux_enum_put,
5772 },
5773 { } /* end */
5774};
5775
Takashi Iwaicb53c622007-08-10 17:21:45 +02005776#ifdef CONFIG_SND_HDA_POWER_SAVE
5777#define alc882_loopbacks alc880_loopbacks
5778#endif
5779
Kailang Yangdf694da2005-12-05 19:42:22 +01005780/* pcm configuration: identiacal with ALC880 */
5781#define alc882_pcm_analog_playback alc880_pcm_analog_playback
5782#define alc882_pcm_analog_capture alc880_pcm_analog_capture
5783#define alc882_pcm_digital_playback alc880_pcm_digital_playback
5784#define alc882_pcm_digital_capture alc880_pcm_digital_capture
5785
5786/*
5787 * configuration and preset
5788 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005789static const char *alc882_models[ALC882_MODEL_LAST] = {
5790 [ALC882_3ST_DIG] = "3stack-dig",
5791 [ALC882_6ST_DIG] = "6stack-dig",
5792 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02005793 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02005794 [ALC882_TARGA] = "targa",
5795 [ALC882_ASUS_A7J] = "asus-a7j",
5796 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01005797 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02005798 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005799 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005800 [ALC882_AUTO] = "auto",
5801};
5802
5803static struct snd_pci_quirk alc882_cfg_tbl[] = {
5804 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02005805 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02005806 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02005807 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005808 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02005809 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01005810 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005811 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
5812 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
5813 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
5814 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01005815 {}
5816};
5817
5818static struct alc_config_preset alc882_presets[] = {
5819 [ALC882_3ST_DIG] = {
5820 .mixers = { alc882_base_mixer },
5821 .init_verbs = { alc882_init_verbs },
5822 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5823 .dac_nids = alc882_dac_nids,
5824 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01005825 .dig_in_nid = ALC882_DIGIN_NID,
5826 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
5827 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005828 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005829 .input_mux = &alc882_capture_source,
5830 },
5831 [ALC882_6ST_DIG] = {
5832 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
5833 .init_verbs = { alc882_init_verbs },
5834 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5835 .dac_nids = alc882_dac_nids,
5836 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01005837 .dig_in_nid = ALC882_DIGIN_NID,
5838 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
5839 .channel_mode = alc882_sixstack_modes,
5840 .input_mux = &alc882_capture_source,
5841 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005842 [ALC882_ARIMA] = {
5843 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
5844 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
5845 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5846 .dac_nids = alc882_dac_nids,
5847 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
5848 .channel_mode = alc882_sixstack_modes,
5849 .input_mux = &alc882_capture_source,
5850 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02005851 [ALC882_W2JC] = {
5852 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
5853 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
5854 alc880_gpio1_init_verbs },
5855 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5856 .dac_nids = alc882_dac_nids,
5857 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5858 .channel_mode = alc880_threestack_modes,
5859 .need_dac_fix = 1,
5860 .input_mux = &alc882_capture_source,
5861 .dig_out_nid = ALC882_DIGOUT_NID,
5862 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02005863 [ALC885_MBP3] = {
5864 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
5865 .init_verbs = { alc885_mbp3_init_verbs,
5866 alc880_gpio1_init_verbs },
5867 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5868 .dac_nids = alc882_dac_nids,
5869 .channel_mode = alc885_mbp_6ch_modes,
5870 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
5871 .input_mux = &alc882_capture_source,
5872 .dig_out_nid = ALC882_DIGOUT_NID,
5873 .dig_in_nid = ALC882_DIGIN_NID,
5874 .unsol_event = alc885_mbp3_unsol_event,
5875 .init_hook = alc885_mbp3_automute,
5876 },
Tobin Davis9102cd12006-12-15 10:02:12 +01005877 [ALC885_MACPRO] = {
5878 .mixers = { alc882_macpro_mixer },
5879 .init_verbs = { alc882_macpro_init_verbs },
5880 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5881 .dac_nids = alc882_dac_nids,
5882 .dig_out_nid = ALC882_DIGOUT_NID,
5883 .dig_in_nid = ALC882_DIGIN_NID,
5884 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
5885 .channel_mode = alc882_ch_modes,
5886 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02005887 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01005888 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005889 [ALC885_IMAC24] = {
5890 .mixers = { alc885_imac24_mixer },
5891 .init_verbs = { alc885_imac24_init_verbs },
5892 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5893 .dac_nids = alc882_dac_nids,
5894 .dig_out_nid = ALC882_DIGOUT_NID,
5895 .dig_in_nid = ALC882_DIGIN_NID,
5896 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
5897 .channel_mode = alc882_ch_modes,
5898 .input_mux = &alc882_capture_source,
5899 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02005900 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005901 },
Kailang Yang272a5272007-05-14 11:00:38 +02005902 [ALC882_TARGA] = {
5903 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
5904 alc882_capture_mixer },
5905 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
5906 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5907 .dac_nids = alc882_dac_nids,
5908 .dig_out_nid = ALC882_DIGOUT_NID,
5909 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
5910 .adc_nids = alc882_adc_nids,
5911 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
5912 .channel_mode = alc882_3ST_6ch_modes,
5913 .need_dac_fix = 1,
5914 .input_mux = &alc882_capture_source,
5915 .unsol_event = alc882_targa_unsol_event,
5916 .init_hook = alc882_targa_automute,
5917 },
5918 [ALC882_ASUS_A7J] = {
5919 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
5920 alc882_capture_mixer },
5921 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
5922 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5923 .dac_nids = alc882_dac_nids,
5924 .dig_out_nid = ALC882_DIGOUT_NID,
5925 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
5926 .adc_nids = alc882_adc_nids,
5927 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
5928 .channel_mode = alc882_3ST_6ch_modes,
5929 .need_dac_fix = 1,
5930 .input_mux = &alc882_capture_source,
5931 },
Takashi Iwai914759b2007-09-06 14:52:04 +02005932 [ALC882_ASUS_A7M] = {
5933 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
5934 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
5935 alc880_gpio1_init_verbs,
5936 alc882_asus_a7m_verbs },
5937 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5938 .dac_nids = alc882_dac_nids,
5939 .dig_out_nid = ALC882_DIGOUT_NID,
5940 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5941 .channel_mode = alc880_threestack_modes,
5942 .need_dac_fix = 1,
5943 .input_mux = &alc882_capture_source,
5944 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005945};
5946
5947
5948/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02005949 * Pin config fixes
5950 */
5951enum {
5952 PINFIX_ABIT_AW9D_MAX
5953};
5954
5955static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
5956 { 0x15, 0x01080104 }, /* side */
5957 { 0x16, 0x01011012 }, /* rear */
5958 { 0x17, 0x01016011 }, /* clfe */
5959 { }
5960};
5961
5962static const struct alc_pincfg *alc882_pin_fixes[] = {
5963 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
5964};
5965
5966static struct snd_pci_quirk alc882_pinfix_tbl[] = {
5967 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
5968 {}
5969};
5970
5971/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005972 * BIOS auto configuration
5973 */
5974static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
5975 hda_nid_t nid, int pin_type,
5976 int dac_idx)
5977{
5978 /* set as output */
5979 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005980 int idx;
5981
Kailang Yangdf694da2005-12-05 19:42:22 +01005982 if (spec->multiout.dac_nids[dac_idx] == 0x25)
5983 idx = 4;
5984 else
5985 idx = spec->multiout.dac_nids[dac_idx] - 2;
5986
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005987 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5988 pin_type);
5989 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5990 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01005991 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
5992
5993}
5994
5995static void alc882_auto_init_multi_out(struct hda_codec *codec)
5996{
5997 struct alc_spec *spec = codec->spec;
5998 int i;
5999
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006000 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006001 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006002 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006003 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006004 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006005 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006006 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006007 }
6008}
6009
6010static void alc882_auto_init_hp_out(struct hda_codec *codec)
6011{
6012 struct alc_spec *spec = codec->spec;
6013 hda_nid_t pin;
6014
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006015 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006016 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006017 /* use dac 0 */
6018 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006019}
6020
6021#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6022#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6023
6024static void alc882_auto_init_analog_input(struct hda_codec *codec)
6025{
6026 struct alc_spec *spec = codec->spec;
6027 int i;
6028
6029 for (i = 0; i < AUTO_PIN_LAST; i++) {
6030 hda_nid_t nid = spec->autocfg.input_pins[i];
6031 if (alc882_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006032 snd_hda_codec_write(codec, nid, 0,
6033 AC_VERB_SET_PIN_WIDGET_CONTROL,
6034 i <= AUTO_PIN_FRONT_MIC ?
6035 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01006036 if (nid != ALC882_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006037 snd_hda_codec_write(codec, nid, 0,
6038 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006039 AMP_OUT_MUTE);
6040 }
6041 }
6042}
6043
Takashi Iwai776e1842007-08-29 15:07:11 +02006044/* add mic boosts if needed */
6045static int alc_auto_add_mic_boost(struct hda_codec *codec)
6046{
6047 struct alc_spec *spec = codec->spec;
6048 int err;
6049 hda_nid_t nid;
6050
6051 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
6052 if (nid) {
6053 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6054 "Mic Boost",
6055 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6056 if (err < 0)
6057 return err;
6058 }
6059 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
6060 if (nid) {
6061 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6062 "Front Mic Boost",
6063 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6064 if (err < 0)
6065 return err;
6066 }
6067 return 0;
6068}
6069
Kailang Yangdf694da2005-12-05 19:42:22 +01006070/* almost identical with ALC880 parser... */
6071static int alc882_parse_auto_config(struct hda_codec *codec)
6072{
6073 struct alc_spec *spec = codec->spec;
6074 int err = alc880_parse_auto_config(codec);
6075
6076 if (err < 0)
6077 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006078 else if (!err)
6079 return 0; /* no config found */
6080
6081 err = alc_auto_add_mic_boost(codec);
6082 if (err < 0)
6083 return err;
6084
6085 /* hack - override the init verbs */
6086 spec->init_verbs[0] = alc882_auto_init_verbs;
6087
6088 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006089}
6090
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006091/* additional initialization for auto-configuration model */
6092static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006093{
Kailang Yangdf694da2005-12-05 19:42:22 +01006094 alc882_auto_init_multi_out(codec);
6095 alc882_auto_init_hp_out(codec);
6096 alc882_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006097}
6098
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099static int patch_alc882(struct hda_codec *codec)
6100{
6101 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006102 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006104 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 if (spec == NULL)
6106 return -ENOMEM;
6107
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 codec->spec = spec;
6109
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006110 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6111 alc882_models,
6112 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113
Kailang Yangdf694da2005-12-05 19:42:22 +01006114 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006115 /* Pick up systems that don't supply PCI SSID */
6116 switch (codec->subsystem_id) {
6117 case 0x106b0c00: /* Mac Pro */
6118 board_config = ALC885_MACPRO;
6119 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006120 case 0x106b1000: /* iMac 24 */
6121 board_config = ALC885_IMAC24;
6122 break;
Takashi Iwai87350ad2007-08-16 18:19:38 +02006123 case 0x106b2c00: /* Macbook Pro rev3 */
6124 board_config = ALC885_MBP3;
6125 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006126 default:
6127 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6128 "trying auto-probe from BIOS...\n");
6129 board_config = ALC882_AUTO;
6130 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006131 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006132
Takashi Iwaif95474e2007-07-10 00:47:43 +02006133 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6134
Kailang Yangdf694da2005-12-05 19:42:22 +01006135 if (board_config == ALC882_AUTO) {
6136 /* automatic parse from the BIOS config */
6137 err = alc882_parse_auto_config(codec);
6138 if (err < 0) {
6139 alc_free(codec);
6140 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006141 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006142 printk(KERN_INFO
6143 "hda_codec: Cannot set up configuration "
6144 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006145 board_config = ALC882_3ST_DIG;
6146 }
6147 }
6148
6149 if (board_config != ALC882_AUTO)
6150 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151
6152 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006153 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6154 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155
6156 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006157 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6158 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006160 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006161 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006162 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006163 /* get type */
6164 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006165 if (wcap != AC_WID_AUD_IN) {
6166 spec->adc_nids = alc882_adc_nids_alt;
6167 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006168 spec->mixers[spec->num_mixers] =
6169 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006170 spec->num_mixers++;
6171 } else {
6172 spec->adc_nids = alc882_adc_nids;
6173 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
6174 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6175 spec->num_mixers++;
6176 }
6177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178
6179 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006180 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006181 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006182#ifdef CONFIG_SND_HDA_POWER_SAVE
6183 if (!spec->loopback.amplist)
6184 spec->loopback.amplist = alc882_loopbacks;
6185#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186
6187 return 0;
6188}
6189
6190/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006191 * ALC883 support
6192 *
6193 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6194 * configuration. Each pin widget can choose any input DACs and a mixer.
6195 * Each ADC is connected from a mixer of all inputs. This makes possible
6196 * 6-channel independent captures.
6197 *
6198 * In addition, an independent DAC for the multi-playback (not used in this
6199 * driver yet).
6200 */
6201#define ALC883_DIGOUT_NID 0x06
6202#define ALC883_DIGIN_NID 0x0a
6203
6204static hda_nid_t alc883_dac_nids[4] = {
6205 /* front, rear, clfe, rear_surr */
6206 0x02, 0x04, 0x03, 0x05
6207};
6208
6209static hda_nid_t alc883_adc_nids[2] = {
6210 /* ADC1-2 */
6211 0x08, 0x09,
6212};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006213
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006214/* input MUX */
6215/* FIXME: should be a matrix-type input source selection */
6216
6217static struct hda_input_mux alc883_capture_source = {
6218 .num_items = 4,
6219 .items = {
6220 { "Mic", 0x0 },
6221 { "Front Mic", 0x1 },
6222 { "Line", 0x2 },
6223 { "CD", 0x4 },
6224 },
6225};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006226
6227static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6228 .num_items = 2,
6229 .items = {
6230 { "Mic", 0x1 },
6231 { "Line", 0x2 },
6232 },
6233};
6234
Kailang Yang272a5272007-05-14 11:00:38 +02006235static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6236 .num_items = 4,
6237 .items = {
6238 { "Mic", 0x0 },
6239 { "iMic", 0x1 },
6240 { "Line", 0x2 },
6241 { "CD", 0x4 },
6242 },
6243};
6244
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006245#define alc883_mux_enum_info alc_mux_enum_info
6246#define alc883_mux_enum_get alc_mux_enum_get
6247
6248static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
6249 struct snd_ctl_elem_value *ucontrol)
6250{
6251 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6252 struct alc_spec *spec = codec->spec;
6253 const struct hda_input_mux *imux = spec->input_mux;
6254 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
6255 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
6256 hda_nid_t nid = capture_mixers[adc_idx];
6257 unsigned int *cur_val = &spec->cur_mux[adc_idx];
6258 unsigned int i, idx;
6259
6260 idx = ucontrol->value.enumerated.item[0];
6261 if (idx >= imux->num_items)
6262 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006263 if (*cur_val == idx)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006264 return 0;
6265 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02006266 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
6267 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006268 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02006269 HDA_AMP_MUTE, v);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006270 }
6271 *cur_val = idx;
6272 return 1;
6273}
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006274
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006275/*
6276 * 2ch mode
6277 */
6278static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6279 { 2, NULL }
6280};
6281
6282/*
6283 * 2ch mode
6284 */
6285static struct hda_verb alc883_3ST_ch2_init[] = {
6286 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6287 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6288 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6289 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6290 { } /* end */
6291};
6292
6293/*
Tobin Davisb2011312007-09-17 12:45:11 +02006294 * 4ch mode
6295 */
6296static struct hda_verb alc883_3ST_ch4_init[] = {
6297 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6298 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6299 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6300 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6301 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6302 { } /* end */
6303};
6304
6305/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006306 * 6ch mode
6307 */
6308static struct hda_verb alc883_3ST_ch6_init[] = {
6309 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6310 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6311 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6312 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6313 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6314 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6315 { } /* end */
6316};
6317
Tobin Davisb2011312007-09-17 12:45:11 +02006318static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006319 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006320 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006321 { 6, alc883_3ST_ch6_init },
6322};
6323
6324/*
6325 * 6ch mode
6326 */
6327static struct hda_verb alc883_sixstack_ch6_init[] = {
6328 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6329 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6330 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6331 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6332 { } /* end */
6333};
6334
6335/*
6336 * 8ch mode
6337 */
6338static struct hda_verb alc883_sixstack_ch8_init[] = {
6339 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6340 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6341 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6342 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6343 { } /* end */
6344};
6345
6346static struct hda_channel_mode alc883_sixstack_modes[2] = {
6347 { 6, alc883_sixstack_ch6_init },
6348 { 8, alc883_sixstack_ch8_init },
6349};
6350
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006351static struct hda_verb alc883_medion_eapd_verbs[] = {
6352 /* eanable EAPD on medion laptop */
6353 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6354 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6355 { }
6356};
6357
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006358/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6359 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6360 */
6361
6362static struct snd_kcontrol_new alc883_base_mixer[] = {
6363 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6364 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6365 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6366 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6367 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6368 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6369 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6370 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6371 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6372 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6373 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6374 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6375 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6376 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6377 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6378 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006379 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006380 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006382 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006383 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6384 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6385 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6386 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6387 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6388 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6389 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6390 {
6391 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6392 /* .name = "Capture Source", */
6393 .name = "Input Source",
6394 .count = 2,
6395 .info = alc883_mux_enum_info,
6396 .get = alc883_mux_enum_get,
6397 .put = alc883_mux_enum_put,
6398 },
6399 { } /* end */
6400};
6401
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006402static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6403 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6404 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6405 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6406 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6407 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6408 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6409 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6410 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6411 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6412 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6413 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6414 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6415 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6416 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6417 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6418 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6419 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6420 {
6421 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6422 /* .name = "Capture Source", */
6423 .name = "Input Source",
6424 .count = 2,
6425 .info = alc883_mux_enum_info,
6426 .get = alc883_mux_enum_get,
6427 .put = alc883_mux_enum_put,
6428 },
6429 { } /* end */
6430};
6431
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006432static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6433 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6434 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6435 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6436 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6437 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6438 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6439 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6440 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006441 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006442 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6443 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006444 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006445 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6446 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6447 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6448 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6449 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6450 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6451 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6452 {
6453 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6454 /* .name = "Capture Source", */
6455 .name = "Input Source",
6456 .count = 2,
6457 .info = alc883_mux_enum_info,
6458 .get = alc883_mux_enum_get,
6459 .put = alc883_mux_enum_put,
6460 },
6461 { } /* end */
6462};
6463
6464static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6465 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6466 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6467 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6468 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6469 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6470 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6471 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6472 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6473 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6474 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6475 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6476 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6477 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6478 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006479 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006480 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6481 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006482 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006483 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6484 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6485 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6486 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6487 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6488 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6489 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6490 {
6491 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6492 /* .name = "Capture Source", */
6493 .name = "Input Source",
6494 .count = 2,
6495 .info = alc883_mux_enum_info,
6496 .get = alc883_mux_enum_get,
6497 .put = alc883_mux_enum_put,
6498 },
6499 { } /* end */
6500};
6501
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006502static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006503 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6504 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6505 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6506 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6507 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6508 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6509 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6510 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6511 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6512 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6513 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6514 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6515 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6516 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006517 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006518 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6519 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006520 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006521 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6522 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6523 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6524 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6525 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6526
6527 {
6528 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6529 /* .name = "Capture Source", */
6530 .name = "Input Source",
6531 .count = 1,
6532 .info = alc883_mux_enum_info,
6533 .get = alc883_mux_enum_get,
6534 .put = alc883_mux_enum_put,
6535 },
6536 { } /* end */
6537};
6538
Kailang Yangccc656c2006-10-17 12:32:26 +02006539static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6540 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6541 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6542 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6543 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6544 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6545 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6546 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6547 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6548 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6549 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6550 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6551 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6552 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6553 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006554 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006555 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6556 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6557 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6558 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6559 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6560 {
6561 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6562 /* .name = "Capture Source", */
6563 .name = "Input Source",
6564 .count = 2,
6565 .info = alc883_mux_enum_info,
6566 .get = alc883_mux_enum_get,
6567 .put = alc883_mux_enum_put,
6568 },
6569 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006570};
Kailang Yangccc656c2006-10-17 12:32:26 +02006571
6572static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6573 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6574 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6575 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6576 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6577 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006579 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006580 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6581 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6582 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6583 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6584 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6585 {
6586 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6587 /* .name = "Capture Source", */
6588 .name = "Input Source",
6589 .count = 2,
6590 .info = alc883_mux_enum_info,
6591 .get = alc883_mux_enum_get,
6592 .put = alc883_mux_enum_put,
6593 },
6594 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006595};
Kailang Yangccc656c2006-10-17 12:32:26 +02006596
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006597static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6598 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6599 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6600 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6601 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
6602 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6603 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6604 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6605 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6606 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6607 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6608 {
6609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6610 /* .name = "Capture Source", */
6611 .name = "Input Source",
6612 .count = 1,
6613 .info = alc883_mux_enum_info,
6614 .get = alc883_mux_enum_get,
6615 .put = alc883_mux_enum_put,
6616 },
6617 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006618};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006619
Kailang Yang272a5272007-05-14 11:00:38 +02006620static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
6621 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6622 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
6623 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6624 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6625 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6626 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6627 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6628 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6629 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6630 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6631 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6632 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6633 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6634 {
6635 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6636 /* .name = "Capture Source", */
6637 .name = "Input Source",
6638 .count = 2,
6639 .info = alc883_mux_enum_info,
6640 .get = alc883_mux_enum_get,
6641 .put = alc883_mux_enum_put,
6642 },
6643 { } /* end */
6644};
6645
6646static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
6647 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6648 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6649 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6650 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6651 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6652 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6653 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6654 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6655 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6656 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6657 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6658 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6659 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6660 {
6661 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6662 /* .name = "Capture Source", */
6663 .name = "Input Source",
6664 .count = 2,
6665 .info = alc883_mux_enum_info,
6666 .get = alc883_mux_enum_get,
6667 .put = alc883_mux_enum_put,
6668 },
6669 { } /* end */
6670};
6671
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006672static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02006673 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6674 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6675 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6676 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6677 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6678 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6679 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6680 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6681 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6682 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6683 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6684 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6685 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6686 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6687 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6688 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6689 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6690 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6691 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6692 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6693 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6694 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6695 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6696 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6697 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6698 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6699 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6700 {
6701 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6702 /* .name = "Capture Source", */
6703 .name = "Input Source",
6704 .count = 2,
6705 .info = alc883_mux_enum_info,
6706 .get = alc883_mux_enum_get,
6707 .put = alc883_mux_enum_put,
6708 },
6709 { } /* end */
6710};
6711
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006712static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006713 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6714 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6715 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6716 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6717 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6718 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6719 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6720 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6721 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6722 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6723 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6724 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6725 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6726 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6727 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6728 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6729 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6730 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6731 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6732 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6733 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6734 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6735 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6736 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6737 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6738 {
6739 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6740 /* .name = "Capture Source", */
6741 .name = "Input Source",
6742 .count = 2,
6743 .info = alc883_mux_enum_info,
6744 .get = alc883_mux_enum_get,
6745 .put = alc883_mux_enum_put,
6746 },
6747 { } /* end */
6748};
6749
Tobin Davis2880a862007-08-07 11:50:26 +02006750static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02006751 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6752 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006753 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006754 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6755 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02006756 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6757 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6758 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006759 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6760 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6761 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6762 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6763 {
6764 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6765 /* .name = "Capture Source", */
6766 .name = "Input Source",
6767 .count = 2,
6768 .info = alc883_mux_enum_info,
6769 .get = alc883_mux_enum_get,
6770 .put = alc883_mux_enum_put,
6771 },
6772 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02006773};
Tobin Davis2880a862007-08-07 11:50:26 +02006774
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006775static struct snd_kcontrol_new alc883_chmode_mixer[] = {
6776 {
6777 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6778 .name = "Channel Mode",
6779 .info = alc_ch_mode_info,
6780 .get = alc_ch_mode_get,
6781 .put = alc_ch_mode_put,
6782 },
6783 { } /* end */
6784};
6785
6786static struct hda_verb alc883_init_verbs[] = {
6787 /* ADC1: mute amp left and right */
6788 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6789 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6790 /* ADC2: mute amp left and right */
6791 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6792 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6793 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6794 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6795 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6796 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6797 /* Rear mixer */
6798 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6799 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6800 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6801 /* CLFE mixer */
6802 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6803 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6804 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6805 /* Side mixer */
6806 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6807 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6808 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6809
Takashi Iwaicb53c622007-08-10 17:21:45 +02006810 /* mute analog input loopbacks */
6811 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6812 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6813 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6814 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6815 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006816
6817 /* Front Pin: output 0 (0x0c) */
6818 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6819 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6820 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6821 /* Rear Pin: output 1 (0x0d) */
6822 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6823 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6824 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6825 /* CLFE Pin: output 2 (0x0e) */
6826 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6827 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6828 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
6829 /* Side Pin: output 3 (0x0f) */
6830 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6831 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6832 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
6833 /* Mic (rear) pin: input vref at 80% */
6834 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6835 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6836 /* Front Mic pin: input vref at 80% */
6837 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6838 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6839 /* Line In pin: input */
6840 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6841 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6842 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6843 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6844 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6845 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
6846 /* CD pin widget for input */
6847 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6848
6849 /* FIXME: use matrix-type input source selection */
6850 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6851 /* Input mixer2 */
6852 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6853 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6854 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
6855 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
6856 /* Input mixer3 */
6857 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6858 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6859 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
6860 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
6861 { }
6862};
6863
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006864/* toggle speaker-output according to the hp-jack state */
6865static void alc883_mitac_hp_automute(struct hda_codec *codec)
6866{
6867 unsigned int present;
6868
6869 present = snd_hda_codec_read(codec, 0x15, 0,
6870 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6871 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6872 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6873 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
6874 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6875}
6876
6877/* auto-toggle front mic */
6878/*
6879static void alc883_mitac_mic_automute(struct hda_codec *codec)
6880{
6881 unsigned int present;
6882 unsigned char bits;
6883
6884 present = snd_hda_codec_read(codec, 0x18, 0,
6885 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6886 bits = present ? HDA_AMP_MUTE : 0;
6887 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
6888}
6889*/
6890
6891static void alc883_mitac_automute(struct hda_codec *codec)
6892{
6893 alc883_mitac_hp_automute(codec);
6894 /* alc883_mitac_mic_automute(codec); */
6895}
6896
6897static void alc883_mitac_unsol_event(struct hda_codec *codec,
6898 unsigned int res)
6899{
6900 switch (res >> 26) {
6901 case ALC880_HP_EVENT:
6902 alc883_mitac_hp_automute(codec);
6903 break;
6904 case ALC880_MIC_EVENT:
6905 /* alc883_mitac_mic_automute(codec); */
6906 break;
6907 }
6908}
6909
6910static struct hda_verb alc883_mitac_verbs[] = {
6911 /* HP */
6912 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6913 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6914 /* Subwoofer */
6915 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
6916 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6917
6918 /* enable unsolicited event */
6919 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6920 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
6921
6922 { } /* end */
6923};
6924
Kailang Yangccc656c2006-10-17 12:32:26 +02006925static struct hda_verb alc883_tagra_verbs[] = {
6926 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6927 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6928
6929 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6930 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6931
6932 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6933 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6934 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6935
6936 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006937 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6938 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6939 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02006940
6941 { } /* end */
6942};
6943
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006944static struct hda_verb alc883_lenovo_101e_verbs[] = {
6945 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6946 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
6947 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
6948 { } /* end */
6949};
6950
Kailang Yang272a5272007-05-14 11:00:38 +02006951static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
6952 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6953 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6954 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6955 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6956 { } /* end */
6957};
6958
6959static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
6960 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6961 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6962 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6963 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
6964 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6965 { } /* end */
6966};
6967
Kailang Yang189609a2007-08-20 11:31:23 +02006968static struct hda_verb alc883_haier_w66_verbs[] = {
6969 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6970 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6971
6972 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6973
6974 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
6975 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6976 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6977 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6978 { } /* end */
6979};
6980
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006981static struct hda_verb alc888_6st_hp_verbs[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02006982 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
6983 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */
6984 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 1 (0x0d) */
6985 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
6986 { }
6987};
6988
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006989static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006990 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
6991 {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
6992 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
6993 { }
6994};
6995
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006996static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006997 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6998 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6999 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7000 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7001 { }
7002};
7003
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007004static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007005 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7006 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7007 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7008 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7009 { }
7010};
7011
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007012static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7013 { 2, alc888_3st_hp_2ch_init },
7014 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007015};
7016
Kailang Yang272a5272007-05-14 11:00:38 +02007017/* toggle front-jack and RCA according to the hp-jack state */
7018static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7019{
7020 unsigned int present;
7021
7022 present = snd_hda_codec_read(codec, 0x1b, 0,
7023 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007024 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7025 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7026 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7027 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007028}
7029
7030/* toggle RCA according to the front-jack state */
7031static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7032{
7033 unsigned int present;
7034
7035 present = snd_hda_codec_read(codec, 0x14, 0,
7036 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007037 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7038 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007039}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007040
Kailang Yang272a5272007-05-14 11:00:38 +02007041static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7042 unsigned int res)
7043{
7044 if ((res >> 26) == ALC880_HP_EVENT)
7045 alc888_lenovo_ms7195_front_automute(codec);
7046 if ((res >> 26) == ALC880_FRONT_EVENT)
7047 alc888_lenovo_ms7195_rca_automute(codec);
7048}
7049
7050static struct hda_verb alc883_medion_md2_verbs[] = {
7051 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7052 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7053
7054 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7055
7056 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7057 { } /* end */
7058};
7059
7060/* toggle speaker-output according to the hp-jack state */
7061static void alc883_medion_md2_automute(struct hda_codec *codec)
7062{
7063 unsigned int present;
7064
7065 present = snd_hda_codec_read(codec, 0x14, 0,
7066 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007067 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7068 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007069}
7070
7071static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7072 unsigned int res)
7073{
7074 if ((res >> 26) == ALC880_HP_EVENT)
7075 alc883_medion_md2_automute(codec);
7076}
7077
Kailang Yangccc656c2006-10-17 12:32:26 +02007078/* toggle speaker-output according to the hp-jack state */
7079static void alc883_tagra_automute(struct hda_codec *codec)
7080{
7081 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007082 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007083
7084 present = snd_hda_codec_read(codec, 0x14, 0,
7085 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007086 bits = present ? HDA_AMP_MUTE : 0;
7087 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7088 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007089 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7090 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007091}
7092
7093static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7094{
7095 if ((res >> 26) == ALC880_HP_EVENT)
7096 alc883_tagra_automute(codec);
7097}
7098
Kailang Yang189609a2007-08-20 11:31:23 +02007099static void alc883_haier_w66_automute(struct hda_codec *codec)
7100{
7101 unsigned int present;
7102 unsigned char bits;
7103
7104 present = snd_hda_codec_read(codec, 0x1b, 0,
7105 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7106 bits = present ? 0x80 : 0;
7107 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7108 0x80, bits);
7109}
7110
7111static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7112 unsigned int res)
7113{
7114 if ((res >> 26) == ALC880_HP_EVENT)
7115 alc883_haier_w66_automute(codec);
7116}
7117
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007118static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7119{
7120 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007121 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007122
7123 present = snd_hda_codec_read(codec, 0x14, 0,
7124 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007125 bits = present ? HDA_AMP_MUTE : 0;
7126 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7127 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007128}
7129
7130static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7131{
7132 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007133 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007134
7135 present = snd_hda_codec_read(codec, 0x1b, 0,
7136 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007137 bits = present ? HDA_AMP_MUTE : 0;
7138 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7139 HDA_AMP_MUTE, bits);
7140 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7141 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007142}
7143
7144static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7145 unsigned int res)
7146{
7147 if ((res >> 26) == ALC880_HP_EVENT)
7148 alc883_lenovo_101e_all_automute(codec);
7149 if ((res >> 26) == ALC880_FRONT_EVENT)
7150 alc883_lenovo_101e_ispeaker_automute(codec);
7151}
7152
Takashi Iwai676a9b52007-08-16 15:23:35 +02007153/* toggle speaker-output according to the hp-jack state */
7154static void alc883_acer_aspire_automute(struct hda_codec *codec)
7155{
7156 unsigned int present;
7157
7158 present = snd_hda_codec_read(codec, 0x14, 0,
7159 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7160 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7161 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7162 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7163 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7164}
7165
7166static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7167 unsigned int res)
7168{
7169 if ((res >> 26) == ALC880_HP_EVENT)
7170 alc883_acer_aspire_automute(codec);
7171}
7172
Kailang Yangd1a991a2007-08-15 16:21:59 +02007173static struct hda_verb alc883_acer_eapd_verbs[] = {
7174 /* HP Pin: output 0 (0x0c) */
7175 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7176 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7177 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7178 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007179 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7180 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007181 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007182 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7183 /* eanable EAPD on medion laptop */
7184 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7185 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007186 /* enable unsolicited event */
7187 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007188 { }
7189};
7190
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007191/*
7192 * generic initialization of ADC, input mixers and output mixers
7193 */
7194static struct hda_verb alc883_auto_init_verbs[] = {
7195 /*
7196 * Unmute ADC0-2 and set the default input to mic-in
7197 */
7198 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7199 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7200 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7201 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7202
Takashi Iwaicb53c622007-08-10 17:21:45 +02007203 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007204 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007205 * Note: PASD motherboards uses the Line In 2 as the input for
7206 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007207 */
7208 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007209 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7210 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7211 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7212 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7213 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007214
7215 /*
7216 * Set up output mixers (0x0c - 0x0f)
7217 */
7218 /* set vol=0 to output mixers */
7219 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7220 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7221 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7222 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7223 /* set up input amps for analog loopback */
7224 /* Amp Indices: DAC = 0, mixer = 1 */
7225 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7226 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7227 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7228 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7229 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7230 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7231 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7232 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7233 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7234 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7235
7236 /* FIXME: use matrix-type input source selection */
7237 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7238 /* Input mixer1 */
7239 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7240 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7241 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007242 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007243 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7244 /* Input mixer2 */
7245 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7246 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7247 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007248 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007249 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007250
7251 { }
7252};
7253
7254/* capture mixer elements */
7255static struct snd_kcontrol_new alc883_capture_mixer[] = {
7256 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7257 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7258 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7259 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7260 {
7261 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7262 /* The multiple "Capture Source" controls confuse alsamixer
7263 * So call somewhat different..
7264 * FIXME: the controls appear in the "playback" view!
7265 */
7266 /* .name = "Capture Source", */
7267 .name = "Input Source",
7268 .count = 2,
7269 .info = alc882_mux_enum_info,
7270 .get = alc882_mux_enum_get,
7271 .put = alc882_mux_enum_put,
7272 },
7273 { } /* end */
7274};
7275
Takashi Iwaicb53c622007-08-10 17:21:45 +02007276#ifdef CONFIG_SND_HDA_POWER_SAVE
7277#define alc883_loopbacks alc880_loopbacks
7278#endif
7279
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007280/* pcm configuration: identiacal with ALC880 */
7281#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7282#define alc883_pcm_analog_capture alc880_pcm_analog_capture
7283#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7284#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7285
7286/*
7287 * configuration and preset
7288 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007289static const char *alc883_models[ALC883_MODEL_LAST] = {
7290 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7291 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7292 [ALC883_3ST_6ch] = "3stack-6ch",
7293 [ALC883_6ST_DIG] = "6stack-dig",
7294 [ALC883_TARGA_DIG] = "targa-dig",
7295 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007296 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007297 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007298 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007299 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007300 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007301 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007302 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7303 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007304 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007305 [ALC888_6ST_HP] = "6stack-hp",
7306 [ALC888_3ST_HP] = "3stack-hp",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007307 [ALC883_MITAC] = "mitac",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007308 [ALC883_AUTO] = "auto",
7309};
7310
7311static struct snd_pci_quirk alc883_cfg_tbl[] = {
7312 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007313 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7314 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7315 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7316 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Tobin Davisfebe3372007-06-12 11:27:46 +02007317 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007318 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7319 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
7320 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
7321 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007322 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007323 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7324 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7325 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007326 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007327 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7328 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7329 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
7330 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
7331 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7332 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7333 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7334 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7335 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7336 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7337 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7338 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7339 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007340 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7341 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007342 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007343 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007344 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007345 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007346 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
7347 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007348 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007349 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Kailang Yang272a5272007-05-14 11:00:38 +02007350 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007351 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007352 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7353 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007354 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Kailang Yang189609a2007-08-20 11:31:23 +02007355 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007356 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007357 {}
7358};
7359
7360static struct alc_config_preset alc883_presets[] = {
7361 [ALC883_3ST_2ch_DIG] = {
7362 .mixers = { alc883_3ST_2ch_mixer },
7363 .init_verbs = { alc883_init_verbs },
7364 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7365 .dac_nids = alc883_dac_nids,
7366 .dig_out_nid = ALC883_DIGOUT_NID,
7367 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7368 .adc_nids = alc883_adc_nids,
7369 .dig_in_nid = ALC883_DIGIN_NID,
7370 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7371 .channel_mode = alc883_3ST_2ch_modes,
7372 .input_mux = &alc883_capture_source,
7373 },
7374 [ALC883_3ST_6ch_DIG] = {
7375 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7376 .init_verbs = { alc883_init_verbs },
7377 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7378 .dac_nids = alc883_dac_nids,
7379 .dig_out_nid = ALC883_DIGOUT_NID,
7380 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7381 .adc_nids = alc883_adc_nids,
7382 .dig_in_nid = ALC883_DIGIN_NID,
7383 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7384 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007385 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007386 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007387 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007388 [ALC883_3ST_6ch] = {
7389 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7390 .init_verbs = { alc883_init_verbs },
7391 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7392 .dac_nids = alc883_dac_nids,
7393 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7394 .adc_nids = alc883_adc_nids,
7395 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7396 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007397 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007398 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007399 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007400 [ALC883_6ST_DIG] = {
7401 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7402 .init_verbs = { alc883_init_verbs },
7403 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7404 .dac_nids = alc883_dac_nids,
7405 .dig_out_nid = ALC883_DIGOUT_NID,
7406 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7407 .adc_nids = alc883_adc_nids,
7408 .dig_in_nid = ALC883_DIGIN_NID,
7409 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7410 .channel_mode = alc883_sixstack_modes,
7411 .input_mux = &alc883_capture_source,
7412 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007413 [ALC883_TARGA_DIG] = {
7414 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7415 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7416 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7417 .dac_nids = alc883_dac_nids,
7418 .dig_out_nid = ALC883_DIGOUT_NID,
7419 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7420 .adc_nids = alc883_adc_nids,
7421 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7422 .channel_mode = alc883_3ST_6ch_modes,
7423 .need_dac_fix = 1,
7424 .input_mux = &alc883_capture_source,
7425 .unsol_event = alc883_tagra_unsol_event,
7426 .init_hook = alc883_tagra_automute,
7427 },
7428 [ALC883_TARGA_2ch_DIG] = {
7429 .mixers = { alc883_tagra_2ch_mixer},
7430 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7431 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7432 .dac_nids = alc883_dac_nids,
7433 .dig_out_nid = ALC883_DIGOUT_NID,
7434 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7435 .adc_nids = alc883_adc_nids,
7436 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7437 .channel_mode = alc883_3ST_2ch_modes,
7438 .input_mux = &alc883_capture_source,
7439 .unsol_event = alc883_tagra_unsol_event,
7440 .init_hook = alc883_tagra_automute,
7441 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007442 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007443 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007444 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7445 * and the headphone jack. Turn this on and rely on the
7446 * standard mute methods whenever the user wants to turn
7447 * these outputs off.
7448 */
7449 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7450 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7451 .dac_nids = alc883_dac_nids,
7452 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7453 .adc_nids = alc883_adc_nids,
7454 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7455 .channel_mode = alc883_3ST_2ch_modes,
7456 .input_mux = &alc883_capture_source,
7457 },
Tobin Davis2880a862007-08-07 11:50:26 +02007458 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007459 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007460 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007461 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7462 .dac_nids = alc883_dac_nids,
7463 .dig_out_nid = ALC883_DIGOUT_NID,
7464 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7465 .adc_nids = alc883_adc_nids,
7466 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7467 .channel_mode = alc883_3ST_2ch_modes,
7468 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007469 .unsol_event = alc883_acer_aspire_unsol_event,
7470 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007471 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007472 [ALC883_MEDION] = {
7473 .mixers = { alc883_fivestack_mixer,
7474 alc883_chmode_mixer },
7475 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007476 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007477 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7478 .dac_nids = alc883_dac_nids,
7479 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7480 .adc_nids = alc883_adc_nids,
7481 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7482 .channel_mode = alc883_sixstack_modes,
7483 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007484 },
Kailang Yang272a5272007-05-14 11:00:38 +02007485 [ALC883_MEDION_MD2] = {
7486 .mixers = { alc883_medion_md2_mixer},
7487 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7488 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7489 .dac_nids = alc883_dac_nids,
7490 .dig_out_nid = ALC883_DIGOUT_NID,
7491 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7492 .adc_nids = alc883_adc_nids,
7493 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7494 .channel_mode = alc883_3ST_2ch_modes,
7495 .input_mux = &alc883_capture_source,
7496 .unsol_event = alc883_medion_md2_unsol_event,
7497 .init_hook = alc883_medion_md2_automute,
7498 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007499 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007500 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007501 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7502 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7503 .dac_nids = alc883_dac_nids,
7504 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7505 .adc_nids = alc883_adc_nids,
7506 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7507 .channel_mode = alc883_3ST_2ch_modes,
7508 .input_mux = &alc883_capture_source,
7509 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007510 [ALC883_LENOVO_101E_2ch] = {
7511 .mixers = { alc883_lenovo_101e_2ch_mixer},
7512 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7513 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7514 .dac_nids = alc883_dac_nids,
7515 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7516 .adc_nids = alc883_adc_nids,
7517 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7518 .channel_mode = alc883_3ST_2ch_modes,
7519 .input_mux = &alc883_lenovo_101e_capture_source,
7520 .unsol_event = alc883_lenovo_101e_unsol_event,
7521 .init_hook = alc883_lenovo_101e_all_automute,
7522 },
Kailang Yang272a5272007-05-14 11:00:38 +02007523 [ALC883_LENOVO_NB0763] = {
7524 .mixers = { alc883_lenovo_nb0763_mixer },
7525 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7526 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7527 .dac_nids = alc883_dac_nids,
7528 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7529 .adc_nids = alc883_adc_nids,
7530 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7531 .channel_mode = alc883_3ST_2ch_modes,
7532 .need_dac_fix = 1,
7533 .input_mux = &alc883_lenovo_nb0763_capture_source,
7534 .unsol_event = alc883_medion_md2_unsol_event,
7535 .init_hook = alc883_medion_md2_automute,
7536 },
7537 [ALC888_LENOVO_MS7195_DIG] = {
7538 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7539 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7540 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7541 .dac_nids = alc883_dac_nids,
7542 .dig_out_nid = ALC883_DIGOUT_NID,
7543 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7544 .adc_nids = alc883_adc_nids,
7545 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7546 .channel_mode = alc883_3ST_6ch_modes,
7547 .need_dac_fix = 1,
7548 .input_mux = &alc883_capture_source,
7549 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7550 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007551 },
7552 [ALC883_HAIER_W66] = {
7553 .mixers = { alc883_tagra_2ch_mixer},
7554 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7555 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7556 .dac_nids = alc883_dac_nids,
7557 .dig_out_nid = ALC883_DIGOUT_NID,
7558 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7559 .adc_nids = alc883_adc_nids,
7560 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7561 .channel_mode = alc883_3ST_2ch_modes,
7562 .input_mux = &alc883_capture_source,
7563 .unsol_event = alc883_haier_w66_unsol_event,
7564 .init_hook = alc883_haier_w66_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02007565 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007566 [ALC888_6ST_HP] = {
7567 .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
7568 .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007569 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7570 .dac_nids = alc883_dac_nids,
7571 .dig_out_nid = ALC883_DIGOUT_NID,
7572 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7573 .adc_nids = alc883_adc_nids,
7574 .dig_in_nid = ALC883_DIGIN_NID,
7575 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7576 .channel_mode = alc883_sixstack_modes,
7577 .input_mux = &alc883_capture_source,
7578 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007579 [ALC888_3ST_HP] = {
7580 .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
7581 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007582 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7583 .dac_nids = alc883_dac_nids,
7584 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7585 .adc_nids = alc883_adc_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007586 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7587 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007588 .need_dac_fix = 1,
7589 .input_mux = &alc883_capture_source,
7590 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007591 [ALC883_MITAC] = {
7592 .mixers = { alc883_mitac_mixer },
7593 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
7594 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7595 .dac_nids = alc883_dac_nids,
7596 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7597 .adc_nids = alc883_adc_nids,
7598 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7599 .channel_mode = alc883_3ST_2ch_modes,
7600 .input_mux = &alc883_capture_source,
7601 .unsol_event = alc883_mitac_unsol_event,
7602 .init_hook = alc883_mitac_automute,
7603 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007604};
7605
7606
7607/*
7608 * BIOS auto configuration
7609 */
7610static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
7611 hda_nid_t nid, int pin_type,
7612 int dac_idx)
7613{
7614 /* set as output */
7615 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007616 int idx;
7617
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007618 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7619 idx = 4;
7620 else
7621 idx = spec->multiout.dac_nids[dac_idx] - 2;
7622
7623 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
7624 pin_type);
7625 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7626 AMP_OUT_UNMUTE);
7627 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7628
7629}
7630
7631static void alc883_auto_init_multi_out(struct hda_codec *codec)
7632{
7633 struct alc_spec *spec = codec->spec;
7634 int i;
7635
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007636 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007637 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007638 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007639 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007640 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007641 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007642 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007643 }
7644}
7645
7646static void alc883_auto_init_hp_out(struct hda_codec *codec)
7647{
7648 struct alc_spec *spec = codec->spec;
7649 hda_nid_t pin;
7650
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007651 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007652 if (pin) /* connect to front */
7653 /* use dac 0 */
7654 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
7655}
7656
7657#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
7658#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
7659
7660static void alc883_auto_init_analog_input(struct hda_codec *codec)
7661{
7662 struct alc_spec *spec = codec->spec;
7663 int i;
7664
7665 for (i = 0; i < AUTO_PIN_LAST; i++) {
7666 hda_nid_t nid = spec->autocfg.input_pins[i];
7667 if (alc883_is_input_pin(nid)) {
7668 snd_hda_codec_write(codec, nid, 0,
7669 AC_VERB_SET_PIN_WIDGET_CONTROL,
7670 (i <= AUTO_PIN_FRONT_MIC ?
7671 PIN_VREF80 : PIN_IN));
7672 if (nid != ALC883_PIN_CD_NID)
7673 snd_hda_codec_write(codec, nid, 0,
7674 AC_VERB_SET_AMP_GAIN_MUTE,
7675 AMP_OUT_MUTE);
7676 }
7677 }
7678}
7679
7680/* almost identical with ALC880 parser... */
7681static int alc883_parse_auto_config(struct hda_codec *codec)
7682{
7683 struct alc_spec *spec = codec->spec;
7684 int err = alc880_parse_auto_config(codec);
7685
7686 if (err < 0)
7687 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007688 else if (!err)
7689 return 0; /* no config found */
7690
7691 err = alc_auto_add_mic_boost(codec);
7692 if (err < 0)
7693 return err;
7694
7695 /* hack - override the init verbs */
7696 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007697 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
7698 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02007699
7700 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007701}
7702
7703/* additional initialization for auto-configuration model */
7704static void alc883_auto_init(struct hda_codec *codec)
7705{
7706 alc883_auto_init_multi_out(codec);
7707 alc883_auto_init_hp_out(codec);
7708 alc883_auto_init_analog_input(codec);
7709}
7710
7711static int patch_alc883(struct hda_codec *codec)
7712{
7713 struct alc_spec *spec;
7714 int err, board_config;
7715
7716 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
7717 if (spec == NULL)
7718 return -ENOMEM;
7719
7720 codec->spec = spec;
7721
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007722 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
7723 alc883_models,
7724 alc883_cfg_tbl);
7725 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007726 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
7727 "trying auto-probe from BIOS...\n");
7728 board_config = ALC883_AUTO;
7729 }
7730
7731 if (board_config == ALC883_AUTO) {
7732 /* automatic parse from the BIOS config */
7733 err = alc883_parse_auto_config(codec);
7734 if (err < 0) {
7735 alc_free(codec);
7736 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007737 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007738 printk(KERN_INFO
7739 "hda_codec: Cannot set up configuration "
7740 "from BIOS. Using base mode...\n");
7741 board_config = ALC883_3ST_2ch_DIG;
7742 }
7743 }
7744
7745 if (board_config != ALC883_AUTO)
7746 setup_preset(spec, &alc883_presets[board_config]);
7747
7748 spec->stream_name_analog = "ALC883 Analog";
7749 spec->stream_analog_playback = &alc883_pcm_analog_playback;
7750 spec->stream_analog_capture = &alc883_pcm_analog_capture;
7751
7752 spec->stream_name_digital = "ALC883 Digital";
7753 spec->stream_digital_playback = &alc883_pcm_digital_playback;
7754 spec->stream_digital_capture = &alc883_pcm_digital_capture;
7755
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007756 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007757 spec->adc_nids = alc883_adc_nids;
7758 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
7759 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007760
7761 codec->patch_ops = alc_patch_ops;
7762 if (board_config == ALC883_AUTO)
7763 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007764#ifdef CONFIG_SND_HDA_POWER_SAVE
7765 if (!spec->loopback.amplist)
7766 spec->loopback.amplist = alc883_loopbacks;
7767#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007768
7769 return 0;
7770}
7771
7772/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007773 * ALC262 support
7774 */
7775
7776#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
7777#define ALC262_DIGIN_NID ALC880_DIGIN_NID
7778
7779#define alc262_dac_nids alc260_dac_nids
7780#define alc262_adc_nids alc882_adc_nids
7781#define alc262_adc_nids_alt alc882_adc_nids_alt
7782
7783#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01007784#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01007785
7786static struct snd_kcontrol_new alc262_base_mixer[] = {
7787 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7788 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7789 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7790 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7791 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7792 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7793 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7794 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007795 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01007796 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7797 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007798 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01007799 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
7800 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
7801 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
7802 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7803 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7804 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01007805 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01007806};
7807
Kailang Yangccc656c2006-10-17 12:32:26 +02007808static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
7809 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7810 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7811 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7812 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7813 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7814 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7815 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7816 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007817 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007818 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7819 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007820 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007821 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
7822 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
7823 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
7824 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7825 { } /* end */
7826};
7827
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007828static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
7829 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7830 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7831 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7832 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7833 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
7834
7835 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7836 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007837 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007838 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7839 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007840 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007841 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7842 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7843 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7844 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7845 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
7846 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
7847 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
7848 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
7849 { } /* end */
7850};
7851
Kailang Yangcd7509a2007-01-26 18:33:17 +01007852static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
7853 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7854 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7855 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7856 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7857 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7858 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
7859 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
7860 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007861 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01007862 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7863 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
7864 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7865 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7866 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
7867 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
7868 { } /* end */
7869};
7870
7871static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
7872 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7873 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007874 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01007875 { } /* end */
7876};
7877
Kailang Yang66d2a9d2007-11-14 12:06:21 +01007878static struct hda_bind_ctls alc262_hp_t5735_bind_front_vol = {
7879 .ops = &snd_hda_bind_vol,
7880 .values = {
7881 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
7882 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
7883 0
7884 },
7885};
7886
7887static struct hda_bind_ctls alc262_hp_t5735_bind_front_sw = {
7888 .ops = &snd_hda_bind_sw,
7889 .values = {
7890 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
7891 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
7892 0
7893 },
7894};
7895
7896/* mute/unmute internal speaker according to the hp jack and mute state */
7897static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
7898{
7899 struct alc_spec *spec = codec->spec;
7900 unsigned int mute;
7901
7902 if (force || !spec->sense_updated) {
7903 unsigned int present;
7904 present = snd_hda_codec_read(codec, 0x15, 0,
7905 AC_VERB_GET_PIN_SENSE, 0);
7906 spec->jack_present = (present & 0x80000000) != 0;
7907 spec->sense_updated = 1;
7908 }
7909 if (spec->jack_present)
7910 mute = (0x7080 | ((0)<<8)); /* mute internal speaker */
7911 else /* unmute internal speaker if necessary */
7912 mute = (0x7000 | ((0)<<8));
7913 snd_hda_codec_write(codec, 0x0c, 0,
7914 AC_VERB_SET_AMP_GAIN_MUTE, mute );
7915}
7916
7917static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
7918 unsigned int res)
7919{
7920 if ((res >> 26) != ALC880_HP_EVENT)
7921 return;
7922 alc262_hp_t5735_automute(codec, 1);
7923}
7924
7925static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
7926{
7927 alc262_hp_t5735_automute(codec, 1);
7928}
7929
7930static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
7931 HDA_BIND_VOL("PCM Playback Volume", &alc262_hp_t5735_bind_front_vol),
7932 HDA_BIND_SW("PCM Playback Switch",&alc262_hp_t5735_bind_front_sw),
7933 HDA_CODEC_VOLUME("LineOut Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7934 HDA_CODEC_MUTE("LineOut Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7935 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7936 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7937 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7938 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7939 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7940 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7941 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7942 { } /* end */
7943};
7944
7945static struct hda_verb alc262_hp_t5735_verbs[] = {
7946 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7947 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7948
7949 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7950 { }
7951};
7952
Takashi Iwai0724ea22007-08-23 00:31:43 +02007953/* bind hp and internal speaker mute (with plug check) */
7954static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
7955 struct snd_ctl_elem_value *ucontrol)
7956{
7957 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
7958 long *valp = ucontrol->value.integer.value;
7959 int change;
7960
7961 /* change hp mute */
7962 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
7963 HDA_AMP_MUTE,
7964 valp[0] ? 0 : HDA_AMP_MUTE);
7965 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
7966 HDA_AMP_MUTE,
7967 valp[1] ? 0 : HDA_AMP_MUTE);
7968 if (change) {
7969 /* change speaker according to HP jack state */
7970 struct alc_spec *spec = codec->spec;
7971 unsigned int mute;
7972 if (spec->jack_present)
7973 mute = HDA_AMP_MUTE;
7974 else
7975 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
7976 HDA_OUTPUT, 0);
7977 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7978 HDA_AMP_MUTE, mute);
7979 }
7980 return change;
7981}
Takashi Iwai5b319542007-07-26 11:49:22 +02007982
Kailang Yang272a5272007-05-14 11:00:38 +02007983static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02007984 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7985 {
7986 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7987 .name = "Master Playback Switch",
7988 .info = snd_hda_mixer_amp_switch_info,
7989 .get = snd_hda_mixer_amp_switch_get,
7990 .put = alc262_sony_master_sw_put,
7991 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
7992 },
Kailang Yang272a5272007-05-14 11:00:38 +02007993 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7994 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7995 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7996 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7997 { } /* end */
7998};
7999
Kailang Yang83c34212007-07-05 11:43:05 +02008000static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8001 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8002 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8003 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8004 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8005 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8006 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8007 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8008 { } /* end */
8009};
Kailang Yang272a5272007-05-14 11:00:38 +02008010
Kailang Yangdf694da2005-12-05 19:42:22 +01008011#define alc262_capture_mixer alc882_capture_mixer
8012#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8013
8014/*
8015 * generic initialization of ADC, input mixers and output mixers
8016 */
8017static struct hda_verb alc262_init_verbs[] = {
8018 /*
8019 * Unmute ADC0-2 and set the default input to mic-in
8020 */
8021 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8022 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8023 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8024 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8025 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8026 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8027
Takashi Iwaicb53c622007-08-10 17:21:45 +02008028 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008029 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008030 * Note: PASD motherboards uses the Line In 2 as the input for
8031 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008032 */
8033 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008034 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8035 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8036 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8037 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8038 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008039
8040 /*
8041 * Set up output mixers (0x0c - 0x0e)
8042 */
8043 /* set vol=0 to output mixers */
8044 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8045 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8046 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8047 /* set up input amps for analog loopback */
8048 /* Amp Indices: DAC = 0, mixer = 1 */
8049 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8050 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8051 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8052 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8053 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8054 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8055
8056 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8057 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8058 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8059 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8060 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8061 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8062
8063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8064 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8065 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8066 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8067 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8068
8069 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8070 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8071
8072 /* FIXME: use matrix-type input source selection */
8073 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8074 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8075 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8076 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8077 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8078 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8079 /* Input mixer2 */
8080 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8081 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8082 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8083 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8084 /* Input mixer3 */
8085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8087 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008088 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008089
8090 { }
8091};
8092
Kailang Yangccc656c2006-10-17 12:32:26 +02008093static struct hda_verb alc262_hippo_unsol_verbs[] = {
8094 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8095 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8096 {}
8097};
8098
8099static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8100 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8101 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8102 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8103
8104 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8105 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8106 {}
8107};
8108
Kailang Yang272a5272007-05-14 11:00:38 +02008109static struct hda_verb alc262_sony_unsol_verbs[] = {
8110 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8111 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8112 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8113
8114 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8115 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8116};
8117
Kailang Yangccc656c2006-10-17 12:32:26 +02008118/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008119static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008120{
8121 struct alc_spec *spec = codec->spec;
8122 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008123 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008124
Takashi Iwai5b319542007-07-26 11:49:22 +02008125 /* need to execute and sync at first */
8126 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8127 present = snd_hda_codec_read(codec, 0x15, 0,
8128 AC_VERB_GET_PIN_SENSE, 0);
8129 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008130 if (spec->jack_present) {
8131 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008132 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8133 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008134 } else {
8135 /* unmute internal speaker if necessary */
8136 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008137 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8138 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008139 }
8140}
8141
8142/* unsolicited event for HP jack sensing */
8143static void alc262_hippo_unsol_event(struct hda_codec *codec,
8144 unsigned int res)
8145{
8146 if ((res >> 26) != ALC880_HP_EVENT)
8147 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008148 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008149}
8150
Takashi Iwai5b319542007-07-26 11:49:22 +02008151static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008152{
Kailang Yangccc656c2006-10-17 12:32:26 +02008153 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008154 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008155
Takashi Iwai5b319542007-07-26 11:49:22 +02008156 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8157 present = snd_hda_codec_read(codec, 0x1b, 0,
8158 AC_VERB_GET_PIN_SENSE, 0);
8159 present = (present & 0x80000000) != 0;
8160 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008161 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008162 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8163 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008164 } else {
8165 /* unmute internal speaker if necessary */
8166 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008167 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8168 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008169 }
8170}
8171
8172/* unsolicited event for HP jack sensing */
8173static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8174 unsigned int res)
8175{
8176 if ((res >> 26) != ALC880_HP_EVENT)
8177 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008178 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008179}
8180
Takashi Iwai834be882006-03-01 14:16:17 +01008181/*
8182 * fujitsu model
8183 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
8184 */
8185
8186#define ALC_HP_EVENT 0x37
8187
8188static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8189 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8190 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8191 {}
8192};
8193
8194static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008195 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008196 .items = {
8197 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008198 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008199 { "CD", 0x4 },
8200 },
8201};
8202
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008203static struct hda_input_mux alc262_HP_capture_source = {
8204 .num_items = 5,
8205 .items = {
8206 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008207 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008208 { "Line", 0x2 },
8209 { "CD", 0x4 },
8210 { "AUX IN", 0x6 },
8211 },
8212};
8213
zhejiangaccbe492007-08-31 12:36:05 +02008214static struct hda_input_mux alc262_HP_D7000_capture_source = {
8215 .num_items = 4,
8216 .items = {
8217 { "Mic", 0x0 },
8218 { "Front Mic", 0x2 },
8219 { "Line", 0x1 },
8220 { "CD", 0x4 },
8221 },
8222};
8223
Takashi Iwai834be882006-03-01 14:16:17 +01008224/* mute/unmute internal speaker according to the hp jack and mute state */
8225static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8226{
8227 struct alc_spec *spec = codec->spec;
8228 unsigned int mute;
8229
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008230 if (force || !spec->sense_updated) {
Takashi Iwai834be882006-03-01 14:16:17 +01008231 unsigned int present;
8232 /* need to execute and sync at first */
8233 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
8234 present = snd_hda_codec_read(codec, 0x14, 0,
8235 AC_VERB_GET_PIN_SENSE, 0);
8236 spec->jack_present = (present & 0x80000000) != 0;
8237 spec->sense_updated = 1;
8238 }
8239 if (spec->jack_present) {
8240 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008241 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8242 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008243 } else {
8244 /* unmute internal speaker if necessary */
8245 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008246 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8247 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008248 }
8249}
8250
8251/* unsolicited event for HP jack sensing */
8252static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8253 unsigned int res)
8254{
8255 if ((res >> 26) != ALC_HP_EVENT)
8256 return;
8257 alc262_fujitsu_automute(codec, 1);
8258}
8259
8260/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008261static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8262 .ops = &snd_hda_bind_vol,
8263 .values = {
8264 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8265 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8266 0
8267 },
8268};
Takashi Iwai834be882006-03-01 14:16:17 +01008269
8270/* bind hp and internal speaker mute (with plug check) */
8271static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8272 struct snd_ctl_elem_value *ucontrol)
8273{
8274 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8275 long *valp = ucontrol->value.integer.value;
8276 int change;
8277
8278 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008279 HDA_AMP_MUTE,
8280 valp[0] ? 0 : HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008281 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008282 HDA_AMP_MUTE,
8283 valp[1] ? 0 : HDA_AMP_MUTE);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008284 if (change)
8285 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008286 return change;
8287}
8288
8289static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008290 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008291 {
8292 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8293 .name = "Master Playback Switch",
8294 .info = snd_hda_mixer_amp_switch_info,
8295 .get = snd_hda_mixer_amp_switch_get,
8296 .put = alc262_fujitsu_master_sw_put,
8297 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8298 },
8299 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8300 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8301 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8302 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8303 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008304 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8305 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8306 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008307 { } /* end */
8308};
8309
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008310/* additional init verbs for Benq laptops */
8311static struct hda_verb alc262_EAPD_verbs[] = {
8312 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8313 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8314 {}
8315};
8316
Kailang Yang83c34212007-07-05 11:43:05 +02008317static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8318 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8319 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8320
8321 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8322 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8323 {}
8324};
8325
Tobin Davisf651b502007-10-26 12:40:47 +02008326/* Samsung Q1 Ultra Vista model setup */
8327static struct snd_kcontrol_new alc262_ultra_mixer[] = {
8328 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8329 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8330 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8331 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8332 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8333 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8334 { } /* end */
8335};
8336
8337static struct hda_verb alc262_ultra_verbs[] = {
8338 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8339 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8340 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8341 /* Mic is on Node 0x19 */
8342 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8343 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
8344 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8345 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
8346 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8347 {0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
8348 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8349 {}
8350};
8351
8352static struct hda_input_mux alc262_ultra_capture_source = {
8353 .num_items = 1,
8354 .items = {
8355 { "Mic", 0x1 },
8356 },
8357};
8358
8359/* mute/unmute internal speaker according to the hp jack and mute state */
8360static void alc262_ultra_automute(struct hda_codec *codec)
8361{
8362 struct alc_spec *spec = codec->spec;
8363 unsigned int mute;
8364 unsigned int present;
8365
8366 /* need to execute and sync at first */
8367 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8368 present = snd_hda_codec_read(codec, 0x15, 0,
8369 AC_VERB_GET_PIN_SENSE, 0);
8370 spec->jack_present = (present & 0x80000000) != 0;
8371 if (spec->jack_present) {
8372 /* mute internal speaker */
8373 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8374 HDA_AMP_MUTE, HDA_AMP_MUTE);
8375 } else {
8376 /* unmute internal speaker if necessary */
8377 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
8378 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8379 HDA_AMP_MUTE, mute);
8380 }
8381}
8382
8383/* unsolicited event for HP jack sensing */
8384static void alc262_ultra_unsol_event(struct hda_codec *codec,
8385 unsigned int res)
8386{
8387 if ((res >> 26) != ALC880_HP_EVENT)
8388 return;
8389 alc262_ultra_automute(codec);
8390}
8391
Kailang Yangdf694da2005-12-05 19:42:22 +01008392/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008393static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
8394 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01008395{
8396 hda_nid_t nid;
8397 int err;
8398
8399 spec->multiout.num_dacs = 1; /* only use one dac */
8400 spec->multiout.dac_nids = spec->private_dac_nids;
8401 spec->multiout.dac_nids[0] = 2;
8402
8403 nid = cfg->line_out_pins[0];
8404 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008405 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8406 "Front Playback Volume",
8407 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
8408 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008409 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008410 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8411 "Front Playback Switch",
8412 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
8413 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008414 return err;
8415 }
8416
Takashi Iwai82bc9552006-03-21 11:24:42 +01008417 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008418 if (nid) {
8419 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008420 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8421 "Speaker Playback Volume",
8422 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8423 HDA_OUTPUT));
8424 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008425 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008426 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8427 "Speaker Playback Switch",
8428 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8429 HDA_OUTPUT));
8430 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008431 return err;
8432 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008433 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8434 "Speaker Playback Switch",
8435 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8436 HDA_OUTPUT));
8437 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008438 return err;
8439 }
8440 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008441 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008442 if (nid) {
8443 /* spec->multiout.hp_nid = 2; */
8444 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008445 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8446 "Headphone Playback Volume",
8447 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8448 HDA_OUTPUT));
8449 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008450 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008451 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8452 "Headphone Playback Switch",
8453 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8454 HDA_OUTPUT));
8455 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008456 return err;
8457 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008458 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8459 "Headphone Playback Switch",
8460 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8461 HDA_OUTPUT));
8462 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008463 return err;
8464 }
8465 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008466 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01008467}
8468
8469/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008470#define alc262_auto_create_analog_input_ctls \
8471 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01008472
8473/*
8474 * generic initialization of ADC, input mixers and output mixers
8475 */
8476static struct hda_verb alc262_volume_init_verbs[] = {
8477 /*
8478 * Unmute ADC0-2 and set the default input to mic-in
8479 */
8480 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8481 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8482 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8483 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8484 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8485 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8486
Takashi Iwaicb53c622007-08-10 17:21:45 +02008487 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008488 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008489 * Note: PASD motherboards uses the Line In 2 as the input for
8490 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008491 */
8492 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008493 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8494 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8495 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8496 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8497 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008498
8499 /*
8500 * Set up output mixers (0x0c - 0x0f)
8501 */
8502 /* set vol=0 to output mixers */
8503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8504 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8505 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8506
8507 /* set up input amps for analog loopback */
8508 /* Amp Indices: DAC = 0, mixer = 1 */
8509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8510 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8511 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8512 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8513 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8514 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8515
8516 /* FIXME: use matrix-type input source selection */
8517 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8518 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8519 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8520 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8521 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8522 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8523 /* Input mixer2 */
8524 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8525 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8526 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8527 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8528 /* Input mixer3 */
8529 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8530 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8533
8534 { }
8535};
8536
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008537static struct hda_verb alc262_HP_BPC_init_verbs[] = {
8538 /*
8539 * Unmute ADC0-2 and set the default input to mic-in
8540 */
8541 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8542 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8543 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8544 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8545 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8546 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8547
Takashi Iwaicb53c622007-08-10 17:21:45 +02008548 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008549 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008550 * Note: PASD motherboards uses the Line In 2 as the input for
8551 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008552 */
8553 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008554 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8555 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8556 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8557 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8558 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8559 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8560 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008561
8562 /*
8563 * Set up output mixers (0x0c - 0x0e)
8564 */
8565 /* set vol=0 to output mixers */
8566 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8567 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8568 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8569
8570 /* set up input amps for analog loopback */
8571 /* Amp Indices: DAC = 0, mixer = 1 */
8572 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8573 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8574 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8575 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8576 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8577 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8578
8579 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8580 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8581 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8582
8583 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8584 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8585
8586 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8587 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8588
8589 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8590 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8591 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8592 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8593 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8594
8595 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8596 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8597 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8598 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8599 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8600 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8601
8602
8603 /* FIXME: use matrix-type input source selection */
8604 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8605 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8606 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8607 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8608 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8609 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8610 /* Input mixer2 */
8611 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8612 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8613 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8614 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8615 /* Input mixer3 */
8616 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8617 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8620
8621 { }
8622};
8623
Kailang Yangcd7509a2007-01-26 18:33:17 +01008624static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
8625 /*
8626 * Unmute ADC0-2 and set the default input to mic-in
8627 */
8628 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8629 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8630 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8631 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8632 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8633 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8634
Takashi Iwaicb53c622007-08-10 17:21:45 +02008635 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01008636 * mixer widget
8637 * Note: PASD motherboards uses the Line In 2 as the input for front
8638 * panel mic (mic 2)
8639 */
8640 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008641 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8642 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8643 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8644 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8645 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8646 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8647 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
8648 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01008649 /*
8650 * Set up output mixers (0x0c - 0x0e)
8651 */
8652 /* set vol=0 to output mixers */
8653 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8654 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8655 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8656
8657 /* set up input amps for analog loopback */
8658 /* Amp Indices: DAC = 0, mixer = 1 */
8659 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8660 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8661 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8662 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8663 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8664 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8665
8666
8667 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
8668 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
8669 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
8670 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
8671 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
8672 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
8673 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
8674
8675 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8676 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8677
8678 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8679 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8680
8681 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
8682 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8683 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8684 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8685 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8686 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8687
8688 /* FIXME: use matrix-type input source selection */
8689 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8690 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8691 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
8692 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
8693 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
8694 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
8695 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
8696 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
8697 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
8698 /* Input mixer2 */
8699 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8700 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8701 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8702 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8703 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8704 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
8705 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
8706 /* Input mixer3 */
8707 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8708 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8709 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8710 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8711 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8712 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
8713 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
8714
8715 { }
8716};
8717
Takashi Iwaicb53c622007-08-10 17:21:45 +02008718#ifdef CONFIG_SND_HDA_POWER_SAVE
8719#define alc262_loopbacks alc880_loopbacks
8720#endif
8721
Kailang Yangdf694da2005-12-05 19:42:22 +01008722/* pcm configuration: identiacal with ALC880 */
8723#define alc262_pcm_analog_playback alc880_pcm_analog_playback
8724#define alc262_pcm_analog_capture alc880_pcm_analog_capture
8725#define alc262_pcm_digital_playback alc880_pcm_digital_playback
8726#define alc262_pcm_digital_capture alc880_pcm_digital_capture
8727
8728/*
8729 * BIOS auto configuration
8730 */
8731static int alc262_parse_auto_config(struct hda_codec *codec)
8732{
8733 struct alc_spec *spec = codec->spec;
8734 int err;
8735 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
8736
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008737 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
8738 alc262_ignore);
8739 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008740 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008741 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01008742 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008743 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
8744 if (err < 0)
8745 return err;
8746 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
8747 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008748 return err;
8749
8750 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
8751
8752 if (spec->autocfg.dig_out_pin)
8753 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
8754 if (spec->autocfg.dig_in_pin)
8755 spec->dig_in_nid = ALC262_DIGIN_NID;
8756
8757 if (spec->kctl_alloc)
8758 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
8759
8760 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02008761 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01008762 spec->input_mux = &spec->private_imux;
8763
Takashi Iwai776e1842007-08-29 15:07:11 +02008764 err = alc_auto_add_mic_boost(codec);
8765 if (err < 0)
8766 return err;
8767
Kailang Yangdf694da2005-12-05 19:42:22 +01008768 return 1;
8769}
8770
8771#define alc262_auto_init_multi_out alc882_auto_init_multi_out
8772#define alc262_auto_init_hp_out alc882_auto_init_hp_out
8773#define alc262_auto_init_analog_input alc882_auto_init_analog_input
8774
8775
8776/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01008777static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01008778{
Kailang Yangdf694da2005-12-05 19:42:22 +01008779 alc262_auto_init_multi_out(codec);
8780 alc262_auto_init_hp_out(codec);
8781 alc262_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01008782}
8783
8784/*
8785 * configuration and preset
8786 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008787static const char *alc262_models[ALC262_MODEL_LAST] = {
8788 [ALC262_BASIC] = "basic",
8789 [ALC262_HIPPO] = "hippo",
8790 [ALC262_HIPPO_1] = "hippo_1",
8791 [ALC262_FUJITSU] = "fujitsu",
8792 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01008793 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01008794 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008795 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02008796 [ALC262_BENQ_T31] = "benq-t31",
8797 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02008798 [ALC262_ULTRA] = "ultra",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008799 [ALC262_AUTO] = "auto",
8800};
8801
8802static struct snd_pci_quirk alc262_cfg_tbl[] = {
8803 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
8804 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02008805 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008806 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
8807 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02008808 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01008809 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01008810 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01008811 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008812 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008813 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008814 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008815 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008816 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008817 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008818 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008819 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008820 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
8821 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
8822 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008823 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
8824 ALC262_HP_TC_T5735),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008825 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008826 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008827 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
8828 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
8829 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008830 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008831 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008832 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02008833 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008834 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01008835 {}
8836};
8837
8838static struct alc_config_preset alc262_presets[] = {
8839 [ALC262_BASIC] = {
8840 .mixers = { alc262_base_mixer },
8841 .init_verbs = { alc262_init_verbs },
8842 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8843 .dac_nids = alc262_dac_nids,
8844 .hp_nid = 0x03,
8845 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8846 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01008847 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01008848 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008849 [ALC262_HIPPO] = {
8850 .mixers = { alc262_base_mixer },
8851 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
8852 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8853 .dac_nids = alc262_dac_nids,
8854 .hp_nid = 0x03,
8855 .dig_out_nid = ALC262_DIGOUT_NID,
8856 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8857 .channel_mode = alc262_modes,
8858 .input_mux = &alc262_capture_source,
8859 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02008860 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02008861 },
8862 [ALC262_HIPPO_1] = {
8863 .mixers = { alc262_hippo1_mixer },
8864 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
8865 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8866 .dac_nids = alc262_dac_nids,
8867 .hp_nid = 0x02,
8868 .dig_out_nid = ALC262_DIGOUT_NID,
8869 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8870 .channel_mode = alc262_modes,
8871 .input_mux = &alc262_capture_source,
8872 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02008873 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02008874 },
Takashi Iwai834be882006-03-01 14:16:17 +01008875 [ALC262_FUJITSU] = {
8876 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008877 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
8878 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01008879 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8880 .dac_nids = alc262_dac_nids,
8881 .hp_nid = 0x03,
8882 .dig_out_nid = ALC262_DIGOUT_NID,
8883 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8884 .channel_mode = alc262_modes,
8885 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01008886 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwai834be882006-03-01 14:16:17 +01008887 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008888 [ALC262_HP_BPC] = {
8889 .mixers = { alc262_HP_BPC_mixer },
8890 .init_verbs = { alc262_HP_BPC_init_verbs },
8891 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8892 .dac_nids = alc262_dac_nids,
8893 .hp_nid = 0x03,
8894 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8895 .channel_mode = alc262_modes,
8896 .input_mux = &alc262_HP_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008897 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008898 [ALC262_HP_BPC_D7000_WF] = {
8899 .mixers = { alc262_HP_BPC_WildWest_mixer },
8900 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
8901 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8902 .dac_nids = alc262_dac_nids,
8903 .hp_nid = 0x03,
8904 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8905 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02008906 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008907 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008908 [ALC262_HP_BPC_D7000_WL] = {
8909 .mixers = { alc262_HP_BPC_WildWest_mixer,
8910 alc262_HP_BPC_WildWest_option_mixer },
8911 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
8912 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8913 .dac_nids = alc262_dac_nids,
8914 .hp_nid = 0x03,
8915 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8916 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02008917 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008918 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008919 [ALC262_HP_TC_T5735] = {
8920 .mixers = { alc262_hp_t5735_mixer },
8921 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
8922 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8923 .dac_nids = alc262_dac_nids,
8924 .hp_nid = 0x03,
8925 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8926 .channel_mode = alc262_modes,
8927 .input_mux = &alc262_capture_source,
8928 .unsol_event = alc262_hp_t5735_unsol_event,
8929 .init_hook = alc262_hp_t5735_init_hook,
8930 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008931 [ALC262_BENQ_ED8] = {
8932 .mixers = { alc262_base_mixer },
8933 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
8934 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8935 .dac_nids = alc262_dac_nids,
8936 .hp_nid = 0x03,
8937 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8938 .channel_mode = alc262_modes,
8939 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008940 },
Kailang Yang272a5272007-05-14 11:00:38 +02008941 [ALC262_SONY_ASSAMD] = {
8942 .mixers = { alc262_sony_mixer },
8943 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
8944 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8945 .dac_nids = alc262_dac_nids,
8946 .hp_nid = 0x02,
8947 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8948 .channel_mode = alc262_modes,
8949 .input_mux = &alc262_capture_source,
8950 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02008951 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02008952 },
8953 [ALC262_BENQ_T31] = {
8954 .mixers = { alc262_benq_t31_mixer },
8955 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
8956 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8957 .dac_nids = alc262_dac_nids,
8958 .hp_nid = 0x03,
8959 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8960 .channel_mode = alc262_modes,
8961 .input_mux = &alc262_capture_source,
8962 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02008963 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02008964 },
Tobin Davisf651b502007-10-26 12:40:47 +02008965 [ALC262_ULTRA] = {
8966 .mixers = { alc262_ultra_mixer },
8967 .init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
8968 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
8969 .dac_nids = alc262_dac_nids,
8970 .hp_nid = 0x03,
8971 .dig_out_nid = ALC262_DIGOUT_NID,
8972 .num_channel_mode = ARRAY_SIZE(alc262_modes),
8973 .channel_mode = alc262_modes,
8974 .input_mux = &alc262_ultra_capture_source,
8975 .unsol_event = alc262_ultra_unsol_event,
8976 .init_hook = alc262_ultra_automute,
8977 },
Kailang Yangdf694da2005-12-05 19:42:22 +01008978};
8979
8980static int patch_alc262(struct hda_codec *codec)
8981{
8982 struct alc_spec *spec;
8983 int board_config;
8984 int err;
8985
Robert P. J. Daydc041e02006-12-19 14:44:15 +01008986 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01008987 if (spec == NULL)
8988 return -ENOMEM;
8989
8990 codec->spec = spec;
8991#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008992 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
8993 * under-run
8994 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008995 {
8996 int tmp;
8997 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
8998 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
8999 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9000 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9001 }
9002#endif
9003
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009004 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9005 alc262_models,
9006 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009007
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009008 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009009 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9010 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009011 board_config = ALC262_AUTO;
9012 }
9013
9014 if (board_config == ALC262_AUTO) {
9015 /* automatic parse from the BIOS config */
9016 err = alc262_parse_auto_config(codec);
9017 if (err < 0) {
9018 alc_free(codec);
9019 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009020 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009021 printk(KERN_INFO
9022 "hda_codec: Cannot set up configuration "
9023 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009024 board_config = ALC262_BASIC;
9025 }
9026 }
9027
9028 if (board_config != ALC262_AUTO)
9029 setup_preset(spec, &alc262_presets[board_config]);
9030
9031 spec->stream_name_analog = "ALC262 Analog";
9032 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9033 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9034
9035 spec->stream_name_digital = "ALC262 Digital";
9036 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9037 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9038
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009039 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009040 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009041 unsigned int wcap = get_wcaps(codec, 0x07);
9042
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009043 /* get type */
9044 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009045 if (wcap != AC_WID_AUD_IN) {
9046 spec->adc_nids = alc262_adc_nids_alt;
9047 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009048 spec->mixers[spec->num_mixers] =
9049 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009050 spec->num_mixers++;
9051 } else {
9052 spec->adc_nids = alc262_adc_nids;
9053 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
9054 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9055 spec->num_mixers++;
9056 }
9057 }
9058
9059 codec->patch_ops = alc_patch_ops;
9060 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009061 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009062#ifdef CONFIG_SND_HDA_POWER_SAVE
9063 if (!spec->loopback.amplist)
9064 spec->loopback.amplist = alc262_loopbacks;
9065#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009066
Kailang Yangdf694da2005-12-05 19:42:22 +01009067 return 0;
9068}
9069
Kailang Yangdf694da2005-12-05 19:42:22 +01009070/*
Kailang Yanga361d842007-06-05 12:30:55 +02009071 * ALC268 channel source setting (2 channel)
9072 */
9073#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9074#define alc268_modes alc260_modes
9075
9076static hda_nid_t alc268_dac_nids[2] = {
9077 /* front, hp */
9078 0x02, 0x03
9079};
9080
9081static hda_nid_t alc268_adc_nids[2] = {
9082 /* ADC0-1 */
9083 0x08, 0x07
9084};
9085
9086static hda_nid_t alc268_adc_nids_alt[1] = {
9087 /* ADC0 */
9088 0x08
9089};
9090
9091static struct snd_kcontrol_new alc268_base_mixer[] = {
9092 /* output mixer control */
9093 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9094 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9095 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9096 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009097 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9098 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9099 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009100 { }
9101};
9102
Kailang Yangd1a991a2007-08-15 16:21:59 +02009103static struct hda_verb alc268_eapd_verbs[] = {
9104 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9105 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9106 { }
9107};
9108
Takashi Iwaid2738092007-08-16 14:59:45 +02009109/* Toshiba specific */
9110#define alc268_toshiba_automute alc262_hippo_automute
9111
9112static struct hda_verb alc268_toshiba_verbs[] = {
9113 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9114 { } /* end */
9115};
9116
9117/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009118/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009119static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9120 .ops = &snd_hda_bind_vol,
9121 .values = {
9122 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9123 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9124 0
9125 },
9126};
9127
Takashi Iwai889c4392007-08-23 18:56:52 +02009128/* mute/unmute internal speaker according to the hp jack and mute state */
9129static void alc268_acer_automute(struct hda_codec *codec, int force)
9130{
9131 struct alc_spec *spec = codec->spec;
9132 unsigned int mute;
9133
9134 if (force || !spec->sense_updated) {
9135 unsigned int present;
9136 present = snd_hda_codec_read(codec, 0x14, 0,
9137 AC_VERB_GET_PIN_SENSE, 0);
9138 spec->jack_present = (present & 0x80000000) != 0;
9139 spec->sense_updated = 1;
9140 }
9141 if (spec->jack_present)
9142 mute = HDA_AMP_MUTE; /* mute internal speaker */
9143 else /* unmute internal speaker if necessary */
9144 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9145 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9146 HDA_AMP_MUTE, mute);
9147}
9148
9149
9150/* bind hp and internal speaker mute (with plug check) */
9151static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9152 struct snd_ctl_elem_value *ucontrol)
9153{
9154 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9155 long *valp = ucontrol->value.integer.value;
9156 int change;
9157
9158 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9159 HDA_AMP_MUTE,
9160 valp[0] ? 0 : HDA_AMP_MUTE);
9161 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9162 HDA_AMP_MUTE,
9163 valp[1] ? 0 : HDA_AMP_MUTE);
9164 if (change)
9165 alc268_acer_automute(codec, 0);
9166 return change;
9167}
Takashi Iwaid2738092007-08-16 14:59:45 +02009168
9169static struct snd_kcontrol_new alc268_acer_mixer[] = {
9170 /* output mixer control */
9171 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9172 {
9173 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9174 .name = "Master Playback Switch",
9175 .info = snd_hda_mixer_amp_switch_info,
9176 .get = snd_hda_mixer_amp_switch_get,
9177 .put = alc268_acer_master_sw_put,
9178 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9179 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009180 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9181 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9182 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009183 { }
9184};
9185
9186static struct hda_verb alc268_acer_verbs[] = {
9187 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9188 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9189
9190 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9191 { }
9192};
9193
9194/* unsolicited event for HP jack sensing */
9195static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9196 unsigned int res)
9197{
Takashi Iwai889c4392007-08-23 18:56:52 +02009198 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009199 return;
9200 alc268_toshiba_automute(codec);
9201}
9202
9203static void alc268_acer_unsol_event(struct hda_codec *codec,
9204 unsigned int res)
9205{
Takashi Iwai889c4392007-08-23 18:56:52 +02009206 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009207 return;
9208 alc268_acer_automute(codec, 1);
9209}
9210
Takashi Iwai889c4392007-08-23 18:56:52 +02009211static void alc268_acer_init_hook(struct hda_codec *codec)
9212{
9213 alc268_acer_automute(codec, 1);
9214}
9215
Kailang Yanga361d842007-06-05 12:30:55 +02009216/*
9217 * generic initialization of ADC, input mixers and output mixers
9218 */
9219static struct hda_verb alc268_base_init_verbs[] = {
9220 /* Unmute DAC0-1 and set vol = 0 */
9221 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9222 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9223 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9224 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9225 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9226 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9227
9228 /*
9229 * Set up output mixers (0x0c - 0x0e)
9230 */
9231 /* set vol=0 to output mixers */
9232 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9233 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9234 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9235 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
9236
9237 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9238 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9239
9240 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9241 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9242 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9243 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9244 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9245 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9246 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9247 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9248
9249 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9250 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9251 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9252 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9253 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9254 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9255 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9256 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9257
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009258 /* Unmute Selector 23h,24h and set the default input to mic-in */
9259
9260 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
9261 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9262 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
9263 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +02009264
Kailang Yanga361d842007-06-05 12:30:55 +02009265 { }
9266};
9267
9268/*
9269 * generic initialization of ADC, input mixers and output mixers
9270 */
9271static struct hda_verb alc268_volume_init_verbs[] = {
9272 /* set output DAC */
9273 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9274 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9275 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9276 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9277
9278 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9279 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9280 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9281 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9282 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9283
9284 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9285 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9286 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9287 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9288 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9289
9290 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9291 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9292 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9293 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9294
9295 /* set PCBEEP vol = 0 */
9296 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
9297
9298 { }
9299};
9300
9301#define alc268_mux_enum_info alc_mux_enum_info
9302#define alc268_mux_enum_get alc_mux_enum_get
9303
9304static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
9305 struct snd_ctl_elem_value *ucontrol)
9306{
9307 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9308 struct alc_spec *spec = codec->spec;
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009309
Kailang Yanga361d842007-06-05 12:30:55 +02009310 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
9311 static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
9312 hda_nid_t nid = capture_mixers[adc_idx];
Kailang Yanga361d842007-06-05 12:30:55 +02009313
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009314 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
9315 nid,
9316 &spec->cur_mux[adc_idx]);
Kailang Yanga361d842007-06-05 12:30:55 +02009317}
9318
9319static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
9320 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9321 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9322 {
9323 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9324 /* The multiple "Capture Source" controls confuse alsamixer
9325 * So call somewhat different..
9326 * FIXME: the controls appear in the "playback" view!
9327 */
9328 /* .name = "Capture Source", */
9329 .name = "Input Source",
9330 .count = 1,
9331 .info = alc268_mux_enum_info,
9332 .get = alc268_mux_enum_get,
9333 .put = alc268_mux_enum_put,
9334 },
9335 { } /* end */
9336};
9337
9338static struct snd_kcontrol_new alc268_capture_mixer[] = {
9339 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9340 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9341 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
9342 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
9343 {
9344 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9345 /* The multiple "Capture Source" controls confuse alsamixer
9346 * So call somewhat different..
9347 * FIXME: the controls appear in the "playback" view!
9348 */
9349 /* .name = "Capture Source", */
9350 .name = "Input Source",
9351 .count = 2,
9352 .info = alc268_mux_enum_info,
9353 .get = alc268_mux_enum_get,
9354 .put = alc268_mux_enum_put,
9355 },
9356 { } /* end */
9357};
9358
9359static struct hda_input_mux alc268_capture_source = {
9360 .num_items = 4,
9361 .items = {
9362 { "Mic", 0x0 },
9363 { "Front Mic", 0x1 },
9364 { "Line", 0x2 },
9365 { "CD", 0x3 },
9366 },
9367};
9368
9369/* create input playback/capture controls for the given pin */
9370static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
9371 const char *ctlname, int idx)
9372{
9373 char name[32];
9374 int err;
9375
9376 sprintf(name, "%s Playback Volume", ctlname);
9377 if (nid == 0x14) {
9378 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9379 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
9380 HDA_OUTPUT));
9381 if (err < 0)
9382 return err;
9383 } else if (nid == 0x15) {
9384 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9385 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
9386 HDA_OUTPUT));
9387 if (err < 0)
9388 return err;
9389 } else
9390 return -1;
9391 sprintf(name, "%s Playback Switch", ctlname);
9392 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
9393 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
9394 if (err < 0)
9395 return err;
9396 return 0;
9397}
9398
9399/* add playback controls from the parsed DAC table */
9400static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
9401 const struct auto_pin_cfg *cfg)
9402{
9403 hda_nid_t nid;
9404 int err;
9405
9406 spec->multiout.num_dacs = 2; /* only use one dac */
9407 spec->multiout.dac_nids = spec->private_dac_nids;
9408 spec->multiout.dac_nids[0] = 2;
9409 spec->multiout.dac_nids[1] = 3;
9410
9411 nid = cfg->line_out_pins[0];
9412 if (nid)
9413 alc268_new_analog_output(spec, nid, "Front", 0);
9414
9415 nid = cfg->speaker_pins[0];
9416 if (nid == 0x1d) {
9417 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9418 "Speaker Playback Volume",
9419 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9420 if (err < 0)
9421 return err;
9422 }
9423 nid = cfg->hp_pins[0];
9424 if (nid)
9425 alc268_new_analog_output(spec, nid, "Headphone", 0);
9426
9427 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
9428 if (nid == 0x16) {
9429 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9430 "Mono Playback Switch",
9431 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
9432 if (err < 0)
9433 return err;
9434 }
9435 return 0;
9436}
9437
9438/* create playback/capture controls for input pins */
9439static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
9440 const struct auto_pin_cfg *cfg)
9441{
9442 struct hda_input_mux *imux = &spec->private_imux;
9443 int i, idx1;
9444
9445 for (i = 0; i < AUTO_PIN_LAST; i++) {
9446 switch(cfg->input_pins[i]) {
9447 case 0x18:
9448 idx1 = 0; /* Mic 1 */
9449 break;
9450 case 0x19:
9451 idx1 = 1; /* Mic 2 */
9452 break;
9453 case 0x1a:
9454 idx1 = 2; /* Line In */
9455 break;
9456 case 0x1c:
9457 idx1 = 3; /* CD */
9458 break;
9459 default:
9460 continue;
9461 }
9462 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
9463 imux->items[imux->num_items].index = idx1;
9464 imux->num_items++;
9465 }
9466 return 0;
9467}
9468
9469static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
9470{
9471 struct alc_spec *spec = codec->spec;
9472 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
9473 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9474 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
9475 unsigned int dac_vol1, dac_vol2;
9476
9477 if (speaker_nid) {
9478 snd_hda_codec_write(codec, speaker_nid, 0,
9479 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
9480 snd_hda_codec_write(codec, 0x0f, 0,
9481 AC_VERB_SET_AMP_GAIN_MUTE,
9482 AMP_IN_UNMUTE(1));
9483 snd_hda_codec_write(codec, 0x10, 0,
9484 AC_VERB_SET_AMP_GAIN_MUTE,
9485 AMP_IN_UNMUTE(1));
9486 } else {
9487 snd_hda_codec_write(codec, 0x0f, 0,
9488 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9489 snd_hda_codec_write(codec, 0x10, 0,
9490 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9491 }
9492
9493 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
9494 if (line_nid == 0x14)
9495 dac_vol2 = AMP_OUT_ZERO;
9496 else if (line_nid == 0x15)
9497 dac_vol1 = AMP_OUT_ZERO;
9498 if (hp_nid == 0x14)
9499 dac_vol2 = AMP_OUT_ZERO;
9500 else if (hp_nid == 0x15)
9501 dac_vol1 = AMP_OUT_ZERO;
9502 if (line_nid != 0x16 || hp_nid != 0x16 ||
9503 spec->autocfg.line_out_pins[1] != 0x16 ||
9504 spec->autocfg.line_out_pins[2] != 0x16)
9505 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
9506
9507 snd_hda_codec_write(codec, 0x02, 0,
9508 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
9509 snd_hda_codec_write(codec, 0x03, 0,
9510 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
9511}
9512
9513/* pcm configuration: identiacal with ALC880 */
9514#define alc268_pcm_analog_playback alc880_pcm_analog_playback
9515#define alc268_pcm_analog_capture alc880_pcm_analog_capture
9516#define alc268_pcm_digital_playback alc880_pcm_digital_playback
9517
9518/*
9519 * BIOS auto configuration
9520 */
9521static int alc268_parse_auto_config(struct hda_codec *codec)
9522{
9523 struct alc_spec *spec = codec->spec;
9524 int err;
9525 static hda_nid_t alc268_ignore[] = { 0 };
9526
9527 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9528 alc268_ignore);
9529 if (err < 0)
9530 return err;
9531 if (!spec->autocfg.line_outs)
9532 return 0; /* can't find valid BIOS pin config */
9533
9534 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
9535 if (err < 0)
9536 return err;
9537 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
9538 if (err < 0)
9539 return err;
9540
9541 spec->multiout.max_channels = 2;
9542
9543 /* digital only support output */
9544 if (spec->autocfg.dig_out_pin)
9545 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
9546
9547 if (spec->kctl_alloc)
9548 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9549
9550 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
9551 spec->num_mux_defs = 1;
9552 spec->input_mux = &spec->private_imux;
9553
Takashi Iwai776e1842007-08-29 15:07:11 +02009554 err = alc_auto_add_mic_boost(codec);
9555 if (err < 0)
9556 return err;
9557
Kailang Yanga361d842007-06-05 12:30:55 +02009558 return 1;
9559}
9560
9561#define alc268_auto_init_multi_out alc882_auto_init_multi_out
9562#define alc268_auto_init_hp_out alc882_auto_init_hp_out
9563#define alc268_auto_init_analog_input alc882_auto_init_analog_input
9564
9565/* init callback for auto-configuration model -- overriding the default init */
9566static void alc268_auto_init(struct hda_codec *codec)
9567{
9568 alc268_auto_init_multi_out(codec);
9569 alc268_auto_init_hp_out(codec);
9570 alc268_auto_init_mono_speaker_out(codec);
9571 alc268_auto_init_analog_input(codec);
9572}
9573
9574/*
9575 * configuration and preset
9576 */
9577static const char *alc268_models[ALC268_MODEL_LAST] = {
9578 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +02009579 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +02009580 [ALC268_ACER] = "acer",
Kailang Yanga361d842007-06-05 12:30:55 +02009581 [ALC268_AUTO] = "auto",
9582};
9583
9584static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009585 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
9586 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
9587 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +02009588 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009589 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +02009590 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +02009591 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Kailang Yanga361d842007-06-05 12:30:55 +02009592 {}
9593};
9594
9595static struct alc_config_preset alc268_presets[] = {
9596 [ALC268_3ST] = {
9597 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
9598 .init_verbs = { alc268_base_init_verbs },
9599 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9600 .dac_nids = alc268_dac_nids,
9601 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9602 .adc_nids = alc268_adc_nids_alt,
9603 .hp_nid = 0x03,
9604 .dig_out_nid = ALC268_DIGOUT_NID,
9605 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9606 .channel_mode = alc268_modes,
9607 .input_mux = &alc268_capture_source,
9608 },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009609 [ALC268_TOSHIBA] = {
9610 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +02009611 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
9612 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009613 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9614 .dac_nids = alc268_dac_nids,
9615 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9616 .adc_nids = alc268_adc_nids_alt,
9617 .hp_nid = 0x03,
9618 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9619 .channel_mode = alc268_modes,
9620 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +02009621 .unsol_event = alc268_toshiba_unsol_event,
9622 .init_hook = alc268_toshiba_automute,
9623 },
9624 [ALC268_ACER] = {
9625 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
9626 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
9627 alc268_acer_verbs },
9628 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9629 .dac_nids = alc268_dac_nids,
9630 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9631 .adc_nids = alc268_adc_nids_alt,
9632 .hp_nid = 0x02,
9633 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9634 .channel_mode = alc268_modes,
9635 .input_mux = &alc268_capture_source,
9636 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +02009637 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009638 },
Kailang Yanga361d842007-06-05 12:30:55 +02009639};
9640
9641static int patch_alc268(struct hda_codec *codec)
9642{
9643 struct alc_spec *spec;
9644 int board_config;
9645 int err;
9646
9647 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
9648 if (spec == NULL)
9649 return -ENOMEM;
9650
9651 codec->spec = spec;
9652
9653 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
9654 alc268_models,
9655 alc268_cfg_tbl);
9656
9657 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
9658 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
9659 "trying auto-probe from BIOS...\n");
9660 board_config = ALC268_AUTO;
9661 }
9662
9663 if (board_config == ALC268_AUTO) {
9664 /* automatic parse from the BIOS config */
9665 err = alc268_parse_auto_config(codec);
9666 if (err < 0) {
9667 alc_free(codec);
9668 return err;
9669 } else if (!err) {
9670 printk(KERN_INFO
9671 "hda_codec: Cannot set up configuration "
9672 "from BIOS. Using base mode...\n");
9673 board_config = ALC268_3ST;
9674 }
9675 }
9676
9677 if (board_config != ALC268_AUTO)
9678 setup_preset(spec, &alc268_presets[board_config]);
9679
9680 spec->stream_name_analog = "ALC268 Analog";
9681 spec->stream_analog_playback = &alc268_pcm_analog_playback;
9682 spec->stream_analog_capture = &alc268_pcm_analog_capture;
9683
9684 spec->stream_name_digital = "ALC268 Digital";
9685 spec->stream_digital_playback = &alc268_pcm_digital_playback;
9686
9687 if (board_config == ALC268_AUTO) {
9688 if (!spec->adc_nids && spec->input_mux) {
9689 /* check whether NID 0x07 is valid */
9690 unsigned int wcap = get_wcaps(codec, 0x07);
9691
9692 /* get type */
9693 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
9694 if (wcap != AC_WID_AUD_IN) {
9695 spec->adc_nids = alc268_adc_nids_alt;
9696 spec->num_adc_nids =
9697 ARRAY_SIZE(alc268_adc_nids_alt);
9698 spec->mixers[spec->num_mixers] =
9699 alc268_capture_alt_mixer;
9700 spec->num_mixers++;
9701 } else {
9702 spec->adc_nids = alc268_adc_nids;
9703 spec->num_adc_nids =
9704 ARRAY_SIZE(alc268_adc_nids);
9705 spec->mixers[spec->num_mixers] =
9706 alc268_capture_mixer;
9707 spec->num_mixers++;
9708 }
9709 }
9710 }
9711 codec->patch_ops = alc_patch_ops;
9712 if (board_config == ALC268_AUTO)
9713 spec->init_hook = alc268_auto_init;
9714
9715 return 0;
9716}
9717
9718/*
Kailang Yangf6a92242007-12-13 16:52:54 +01009719 * ALC269 channel source setting (2 channel)
9720 */
9721#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
9722
9723#define alc269_dac_nids alc260_dac_nids
9724
9725static hda_nid_t alc269_adc_nids[1] = {
9726 /* ADC1 */
9727 0x07,
9728};
9729
9730#define alc269_modes alc260_modes
9731#define alc269_capture_source alc880_lg_lw_capture_source
9732
9733static struct snd_kcontrol_new alc269_base_mixer[] = {
9734 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9735 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9736 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9737 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9738 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9739 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9740 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9741 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9742 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9743 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9744 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9745 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
9746 { } /* end */
9747};
9748
9749/* capture mixer elements */
9750static struct snd_kcontrol_new alc269_capture_mixer[] = {
9751 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9752 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9753 {
9754 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9755 /* The multiple "Capture Source" controls confuse alsamixer
9756 * So call somewhat different..
9757 * FIXME: the controls appear in the "playback" view!
9758 */
9759 /* .name = "Capture Source", */
9760 .name = "Input Source",
9761 .count = 1,
9762 .info = alc_mux_enum_info,
9763 .get = alc_mux_enum_get,
9764 .put = alc_mux_enum_put,
9765 },
9766 { } /* end */
9767};
9768
9769/*
9770 * generic initialization of ADC, input mixers and output mixers
9771 */
9772static struct hda_verb alc269_init_verbs[] = {
9773 /*
9774 * Unmute ADC0 and set the default input to mic-in
9775 */
9776 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9777
9778 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
9779 * analog-loopback mixer widget
9780 * Note: PASD motherboards uses the Line In 2 as the input for
9781 * front panel mic (mic 2)
9782 */
9783 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
9784 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9785 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9786 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9787 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9788 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9789
9790 /*
9791 * Set up output mixers (0x0c - 0x0e)
9792 */
9793 /* set vol=0 to output mixers */
9794 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9795 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9796
9797 /* set up input amps for analog loopback */
9798 /* Amp Indices: DAC = 0, mixer = 1 */
9799 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9800 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9801 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9802 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9803 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9804 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9805
9806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9807 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9808 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9809 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9810 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9811 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9812 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9813
9814 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9815 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9816 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9817 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9818 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9819 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9820 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9821
9822 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9823 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9824
9825 /* FIXME: use matrix-type input source selection */
9826 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
9827 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9828 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9829 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9830 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9831 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9832
9833 /* set EAPD */
9834 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9835 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9836 { }
9837};
9838
9839/* add playback controls from the parsed DAC table */
9840static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
9841 const struct auto_pin_cfg *cfg)
9842{
9843 hda_nid_t nid;
9844 int err;
9845
9846 spec->multiout.num_dacs = 1; /* only use one dac */
9847 spec->multiout.dac_nids = spec->private_dac_nids;
9848 spec->multiout.dac_nids[0] = 2;
9849
9850 nid = cfg->line_out_pins[0];
9851 if (nid) {
9852 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9853 "Front Playback Volume",
9854 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
9855 if (err < 0)
9856 return err;
9857 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9858 "Front Playback Switch",
9859 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9860 if (err < 0)
9861 return err;
9862 }
9863
9864 nid = cfg->speaker_pins[0];
9865 if (nid) {
9866 if (!cfg->line_out_pins[0]) {
9867 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9868 "Speaker Playback Volume",
9869 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
9870 HDA_OUTPUT));
9871 if (err < 0)
9872 return err;
9873 }
9874 if (nid == 0x16) {
9875 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9876 "Speaker Playback Switch",
9877 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9878 HDA_OUTPUT));
9879 if (err < 0)
9880 return err;
9881 } else {
9882 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9883 "Speaker Playback Switch",
9884 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9885 HDA_OUTPUT));
9886 if (err < 0)
9887 return err;
9888 }
9889 }
9890 nid = cfg->hp_pins[0];
9891 if (nid) {
9892 /* spec->multiout.hp_nid = 2; */
9893 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
9894 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9895 "Headphone Playback Volume",
9896 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
9897 HDA_OUTPUT));
9898 if (err < 0)
9899 return err;
9900 }
9901 if (nid == 0x16) {
9902 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9903 "Headphone Playback Switch",
9904 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9905 HDA_OUTPUT));
9906 if (err < 0)
9907 return err;
9908 } else {
9909 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9910 "Headphone Playback Switch",
9911 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9912 HDA_OUTPUT));
9913 if (err < 0)
9914 return err;
9915 }
9916 }
9917 return 0;
9918}
9919
9920#define alc269_auto_create_analog_input_ctls \
9921 alc880_auto_create_analog_input_ctls
9922
9923#ifdef CONFIG_SND_HDA_POWER_SAVE
9924#define alc269_loopbacks alc880_loopbacks
9925#endif
9926
9927/* pcm configuration: identiacal with ALC880 */
9928#define alc269_pcm_analog_playback alc880_pcm_analog_playback
9929#define alc269_pcm_analog_capture alc880_pcm_analog_capture
9930#define alc269_pcm_digital_playback alc880_pcm_digital_playback
9931#define alc269_pcm_digital_capture alc880_pcm_digital_capture
9932
9933/*
9934 * BIOS auto configuration
9935 */
9936static int alc269_parse_auto_config(struct hda_codec *codec)
9937{
9938 struct alc_spec *spec = codec->spec;
9939 int err;
9940 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
9941
9942 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9943 alc269_ignore);
9944 if (err < 0)
9945 return err;
9946
9947 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
9948 if (err < 0)
9949 return err;
9950 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
9951 if (err < 0)
9952 return err;
9953
9954 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9955
9956 if (spec->autocfg.dig_out_pin)
9957 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
9958
9959 if (spec->kctl_alloc)
9960 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9961
9962 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
9963 spec->num_mux_defs = 1;
9964 spec->input_mux = &spec->private_imux;
9965
9966 err = alc_auto_add_mic_boost(codec);
9967 if (err < 0)
9968 return err;
9969
9970 return 1;
9971}
9972
9973#define alc269_auto_init_multi_out alc882_auto_init_multi_out
9974#define alc269_auto_init_hp_out alc882_auto_init_hp_out
9975#define alc269_auto_init_analog_input alc882_auto_init_analog_input
9976
9977
9978/* init callback for auto-configuration model -- overriding the default init */
9979static void alc269_auto_init(struct hda_codec *codec)
9980{
9981 alc269_auto_init_multi_out(codec);
9982 alc269_auto_init_hp_out(codec);
9983 alc269_auto_init_analog_input(codec);
9984}
9985
9986/*
9987 * configuration and preset
9988 */
9989static const char *alc269_models[ALC269_MODEL_LAST] = {
9990 [ALC269_BASIC] = "basic",
9991};
9992
9993static struct snd_pci_quirk alc269_cfg_tbl[] = {
9994 {}
9995};
9996
9997static struct alc_config_preset alc269_presets[] = {
9998 [ALC269_BASIC] = {
9999 .mixers = { alc269_base_mixer },
10000 .init_verbs = { alc269_init_verbs },
10001 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
10002 .dac_nids = alc269_dac_nids,
10003 .hp_nid = 0x03,
10004 .num_channel_mode = ARRAY_SIZE(alc269_modes),
10005 .channel_mode = alc269_modes,
10006 .input_mux = &alc269_capture_source,
10007 },
10008};
10009
10010static int patch_alc269(struct hda_codec *codec)
10011{
10012 struct alc_spec *spec;
10013 int board_config;
10014 int err;
10015
10016 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10017 if (spec == NULL)
10018 return -ENOMEM;
10019
10020 codec->spec = spec;
10021
10022 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
10023 alc269_models,
10024 alc269_cfg_tbl);
10025
10026 if (board_config < 0) {
10027 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
10028 "trying auto-probe from BIOS...\n");
10029 board_config = ALC269_AUTO;
10030 }
10031
10032 if (board_config == ALC269_AUTO) {
10033 /* automatic parse from the BIOS config */
10034 err = alc269_parse_auto_config(codec);
10035 if (err < 0) {
10036 alc_free(codec);
10037 return err;
10038 } else if (!err) {
10039 printk(KERN_INFO
10040 "hda_codec: Cannot set up configuration "
10041 "from BIOS. Using base mode...\n");
10042 board_config = ALC269_BASIC;
10043 }
10044 }
10045
10046 if (board_config != ALC269_AUTO)
10047 setup_preset(spec, &alc269_presets[board_config]);
10048
10049 spec->stream_name_analog = "ALC269 Analog";
10050 spec->stream_analog_playback = &alc269_pcm_analog_playback;
10051 spec->stream_analog_capture = &alc269_pcm_analog_capture;
10052
10053 spec->stream_name_digital = "ALC269 Digital";
10054 spec->stream_digital_playback = &alc269_pcm_digital_playback;
10055 spec->stream_digital_capture = &alc269_pcm_digital_capture;
10056
10057 spec->adc_nids = alc269_adc_nids;
10058 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
10059 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
10060 spec->num_mixers++;
10061
10062 codec->patch_ops = alc_patch_ops;
10063 if (board_config == ALC269_AUTO)
10064 spec->init_hook = alc269_auto_init;
10065#ifdef CONFIG_SND_HDA_POWER_SAVE
10066 if (!spec->loopback.amplist)
10067 spec->loopback.amplist = alc269_loopbacks;
10068#endif
10069
10070 return 0;
10071}
10072
10073/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010074 * ALC861 channel source setting (2/6 channel selection for 3-stack)
10075 */
10076
10077/*
10078 * set the path ways for 2 channel output
10079 * need to set the codec line out and mic 1 pin widgets to inputs
10080 */
10081static struct hda_verb alc861_threestack_ch2_init[] = {
10082 /* set pin widget 1Ah (line in) for input */
10083 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010084 /* set pin widget 18h (mic1/2) for input, for mic also enable
10085 * the vref
10086 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010087 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10088
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010089 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10090#if 0
10091 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10092 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10093#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010094 { } /* end */
10095};
10096/*
10097 * 6ch mode
10098 * need to set the codec line out and mic 1 pin widgets to outputs
10099 */
10100static struct hda_verb alc861_threestack_ch6_init[] = {
10101 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10102 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10103 /* set pin widget 18h (mic1) for output (CLFE)*/
10104 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10105
10106 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010107 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010108
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010109 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10110#if 0
10111 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10112 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10113#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010114 { } /* end */
10115};
10116
10117static struct hda_channel_mode alc861_threestack_modes[2] = {
10118 { 2, alc861_threestack_ch2_init },
10119 { 6, alc861_threestack_ch6_init },
10120};
Takashi Iwai22309c32006-08-09 16:57:28 +020010121/* Set mic1 as input and unmute the mixer */
10122static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
10123 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10124 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10125 { } /* end */
10126};
10127/* Set mic1 as output and mute mixer */
10128static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
10129 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10130 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10131 { } /* end */
10132};
10133
10134static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
10135 { 2, alc861_uniwill_m31_ch2_init },
10136 { 4, alc861_uniwill_m31_ch4_init },
10137};
Kailang Yangdf694da2005-12-05 19:42:22 +010010138
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010139/* Set mic1 and line-in as input and unmute the mixer */
10140static struct hda_verb alc861_asus_ch2_init[] = {
10141 /* set pin widget 1Ah (line in) for input */
10142 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010143 /* set pin widget 18h (mic1/2) for input, for mic also enable
10144 * the vref
10145 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010146 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10147
10148 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10149#if 0
10150 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10151 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10152#endif
10153 { } /* end */
10154};
10155/* Set mic1 nad line-in as output and mute mixer */
10156static struct hda_verb alc861_asus_ch6_init[] = {
10157 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10158 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10159 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10160 /* set pin widget 18h (mic1) for output (CLFE)*/
10161 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10162 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10163 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
10164 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
10165
10166 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10167#if 0
10168 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10169 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10170#endif
10171 { } /* end */
10172};
10173
10174static struct hda_channel_mode alc861_asus_modes[2] = {
10175 { 2, alc861_asus_ch2_init },
10176 { 6, alc861_asus_ch6_init },
10177};
10178
Kailang Yangdf694da2005-12-05 19:42:22 +010010179/* patch-ALC861 */
10180
10181static struct snd_kcontrol_new alc861_base_mixer[] = {
10182 /* output mixer control */
10183 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10184 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10185 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10186 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10187 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10188
10189 /*Input mixer control */
10190 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10191 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10192 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10193 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10194 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10195 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10196 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10197 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10198 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10199 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010200
Kailang Yangdf694da2005-12-05 19:42:22 +010010201 /* Capture mixer control */
10202 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10203 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10204 {
10205 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10206 .name = "Capture Source",
10207 .count = 1,
10208 .info = alc_mux_enum_info,
10209 .get = alc_mux_enum_get,
10210 .put = alc_mux_enum_put,
10211 },
10212 { } /* end */
10213};
10214
10215static struct snd_kcontrol_new alc861_3ST_mixer[] = {
10216 /* output mixer control */
10217 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10218 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10219 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10220 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10221 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10222
10223 /* Input mixer control */
10224 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10225 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10226 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10227 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10228 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10229 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10230 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10231 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10232 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10233 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010234
Kailang Yangdf694da2005-12-05 19:42:22 +010010235 /* Capture mixer control */
10236 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10237 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10238 {
10239 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10240 .name = "Capture Source",
10241 .count = 1,
10242 .info = alc_mux_enum_info,
10243 .get = alc_mux_enum_get,
10244 .put = alc_mux_enum_put,
10245 },
10246 {
10247 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10248 .name = "Channel Mode",
10249 .info = alc_ch_mode_info,
10250 .get = alc_ch_mode_get,
10251 .put = alc_ch_mode_put,
10252 .private_value = ARRAY_SIZE(alc861_threestack_modes),
10253 },
10254 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010255};
10256
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010257static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010258 /* output mixer control */
10259 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10260 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10261 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10262
10263 /*Capture mixer control */
10264 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10265 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10266 {
10267 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10268 .name = "Capture Source",
10269 .count = 1,
10270 .info = alc_mux_enum_info,
10271 .get = alc_mux_enum_get,
10272 .put = alc_mux_enum_put,
10273 },
10274
10275 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010276};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010277
Takashi Iwai22309c32006-08-09 16:57:28 +020010278static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
10279 /* output mixer control */
10280 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10281 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10282 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10283 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10284 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10285
10286 /* Input mixer control */
10287 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10288 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10289 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10290 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10291 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10292 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10293 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10294 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10295 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10296 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010297
Takashi Iwai22309c32006-08-09 16:57:28 +020010298 /* Capture mixer control */
10299 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10300 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10301 {
10302 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10303 .name = "Capture Source",
10304 .count = 1,
10305 .info = alc_mux_enum_info,
10306 .get = alc_mux_enum_get,
10307 .put = alc_mux_enum_put,
10308 },
10309 {
10310 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10311 .name = "Channel Mode",
10312 .info = alc_ch_mode_info,
10313 .get = alc_ch_mode_get,
10314 .put = alc_ch_mode_put,
10315 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
10316 },
10317 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010318};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010319
10320static struct snd_kcontrol_new alc861_asus_mixer[] = {
10321 /* output mixer control */
10322 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10323 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10324 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10325 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10326 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10327
10328 /* Input mixer control */
10329 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10330 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10331 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10332 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10333 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10334 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10335 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10336 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10337 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010338 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
10339
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010340 /* Capture mixer control */
10341 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10342 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10343 {
10344 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10345 .name = "Capture Source",
10346 .count = 1,
10347 .info = alc_mux_enum_info,
10348 .get = alc_mux_enum_get,
10349 .put = alc_mux_enum_put,
10350 },
10351 {
10352 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10353 .name = "Channel Mode",
10354 .info = alc_ch_mode_info,
10355 .get = alc_ch_mode_get,
10356 .put = alc_ch_mode_put,
10357 .private_value = ARRAY_SIZE(alc861_asus_modes),
10358 },
10359 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010360};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010361
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010362/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010363static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010364 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10365 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10366 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
10367 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
10368 { }
10369};
10370
Kailang Yangdf694da2005-12-05 19:42:22 +010010371/*
10372 * generic initialization of ADC, input mixers and output mixers
10373 */
10374static struct hda_verb alc861_base_init_verbs[] = {
10375 /*
10376 * Unmute ADC0 and set the default input to mic-in
10377 */
10378 /* port-A for surround (rear panel) */
10379 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10380 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
10381 /* port-B for mic-in (rear panel) with vref */
10382 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10383 /* port-C for line-in (rear panel) */
10384 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10385 /* port-D for Front */
10386 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10387 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10388 /* port-E for HP out (front panel) */
10389 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10390 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010391 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010392 /* port-F for mic-in (front panel) with vref */
10393 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10394 /* port-G for CLFE (rear panel) */
10395 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10396 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
10397 /* port-H for side (rear panel) */
10398 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10399 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
10400 /* CD-in */
10401 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10402 /* route front mic to ADC1*/
10403 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10404 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10405
10406 /* Unmute DAC0~3 & spdif out*/
10407 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10408 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10409 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10410 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10411 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10412
10413 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10414 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10415 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10416 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10417 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10418
10419 /* Unmute Stereo Mixer 15 */
10420 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10421 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10422 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010423 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010010424
10425 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10426 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10427 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10428 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10429 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10430 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10431 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10432 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010433 /* hp used DAC 3 (Front) */
10434 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010435 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10436
10437 { }
10438};
10439
10440static struct hda_verb alc861_threestack_init_verbs[] = {
10441 /*
10442 * Unmute ADC0 and set the default input to mic-in
10443 */
10444 /* port-A for surround (rear panel) */
10445 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10446 /* port-B for mic-in (rear panel) with vref */
10447 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10448 /* port-C for line-in (rear panel) */
10449 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10450 /* port-D for Front */
10451 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10452 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10453 /* port-E for HP out (front panel) */
10454 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10455 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010456 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010457 /* port-F for mic-in (front panel) with vref */
10458 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10459 /* port-G for CLFE (rear panel) */
10460 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10461 /* port-H for side (rear panel) */
10462 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10463 /* CD-in */
10464 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10465 /* route front mic to ADC1*/
10466 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10467 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10468 /* Unmute DAC0~3 & spdif out*/
10469 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10470 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10471 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10472 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10473 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10474
10475 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10476 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10477 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10478 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10479 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10480
10481 /* Unmute Stereo Mixer 15 */
10482 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10483 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10484 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010485 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010010486
10487 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10488 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10489 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10490 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10491 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10492 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10493 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10494 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010495 /* hp used DAC 3 (Front) */
10496 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010497 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10498 { }
10499};
Takashi Iwai22309c32006-08-09 16:57:28 +020010500
10501static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
10502 /*
10503 * Unmute ADC0 and set the default input to mic-in
10504 */
10505 /* port-A for surround (rear panel) */
10506 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10507 /* port-B for mic-in (rear panel) with vref */
10508 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10509 /* port-C for line-in (rear panel) */
10510 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10511 /* port-D for Front */
10512 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10513 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10514 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010515 /* this has to be set to VREF80 */
10516 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020010517 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010518 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020010519 /* port-F for mic-in (front panel) with vref */
10520 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10521 /* port-G for CLFE (rear panel) */
10522 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10523 /* port-H for side (rear panel) */
10524 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10525 /* CD-in */
10526 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10527 /* route front mic to ADC1*/
10528 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10529 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10530 /* Unmute DAC0~3 & spdif out*/
10531 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10532 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10533 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10534 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10535 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10536
10537 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10538 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10539 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10540 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10541 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10542
10543 /* Unmute Stereo Mixer 15 */
10544 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10545 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10546 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010547 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020010548
10549 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10550 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10551 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10552 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10553 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10554 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10555 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10556 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010557 /* hp used DAC 3 (Front) */
10558 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020010559 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10560 { }
10561};
10562
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010563static struct hda_verb alc861_asus_init_verbs[] = {
10564 /*
10565 * Unmute ADC0 and set the default input to mic-in
10566 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010567 /* port-A for surround (rear panel)
10568 * according to codec#0 this is the HP jack
10569 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010570 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
10571 /* route front PCM to HP */
10572 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
10573 /* port-B for mic-in (rear panel) with vref */
10574 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10575 /* port-C for line-in (rear panel) */
10576 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10577 /* port-D for Front */
10578 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10579 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10580 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010581 /* this has to be set to VREF80 */
10582 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010583 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010584 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010585 /* port-F for mic-in (front panel) with vref */
10586 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10587 /* port-G for CLFE (rear panel) */
10588 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10589 /* port-H for side (rear panel) */
10590 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10591 /* CD-in */
10592 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10593 /* route front mic to ADC1*/
10594 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10595 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10596 /* Unmute DAC0~3 & spdif out*/
10597 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10598 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10599 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10600 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10601 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10602 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10603 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10604 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10605 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10606 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10607
10608 /* Unmute Stereo Mixer 15 */
10609 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10610 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10611 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010612 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010613
10614 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10615 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10616 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10617 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10618 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10619 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10620 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10621 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010622 /* hp used DAC 3 (Front) */
10623 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010624 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10625 { }
10626};
10627
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010628/* additional init verbs for ASUS laptops */
10629static struct hda_verb alc861_asus_laptop_init_verbs[] = {
10630 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
10631 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
10632 { }
10633};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010634
Kailang Yangdf694da2005-12-05 19:42:22 +010010635/*
10636 * generic initialization of ADC, input mixers and output mixers
10637 */
10638static struct hda_verb alc861_auto_init_verbs[] = {
10639 /*
10640 * Unmute ADC0 and set the default input to mic-in
10641 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010642 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010010643 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10644
10645 /* Unmute DAC0~3 & spdif out*/
10646 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10647 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10648 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10649 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10650 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10651
10652 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10653 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10654 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10655 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10656 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10657
10658 /* Unmute Stereo Mixer 15 */
10659 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10660 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10661 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10662 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
10663
10664 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10665 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10666 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10667 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10668 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10669 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10670 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10671 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10672
10673 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10674 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010675 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10676 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010677 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10678 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010679 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10680 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010681
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010682 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010683
10684 { }
10685};
10686
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010687static struct hda_verb alc861_toshiba_init_verbs[] = {
10688 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010689
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010690 { }
10691};
10692
10693/* toggle speaker-output according to the hp-jack state */
10694static void alc861_toshiba_automute(struct hda_codec *codec)
10695{
10696 unsigned int present;
10697
10698 present = snd_hda_codec_read(codec, 0x0f, 0,
10699 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020010700 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
10701 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
10702 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
10703 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010704}
10705
10706static void alc861_toshiba_unsol_event(struct hda_codec *codec,
10707 unsigned int res)
10708{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010709 if ((res >> 26) == ALC880_HP_EVENT)
10710 alc861_toshiba_automute(codec);
10711}
10712
Kailang Yangdf694da2005-12-05 19:42:22 +010010713/* pcm configuration: identiacal with ALC880 */
10714#define alc861_pcm_analog_playback alc880_pcm_analog_playback
10715#define alc861_pcm_analog_capture alc880_pcm_analog_capture
10716#define alc861_pcm_digital_playback alc880_pcm_digital_playback
10717#define alc861_pcm_digital_capture alc880_pcm_digital_capture
10718
10719
10720#define ALC861_DIGOUT_NID 0x07
10721
10722static struct hda_channel_mode alc861_8ch_modes[1] = {
10723 { 8, NULL }
10724};
10725
10726static hda_nid_t alc861_dac_nids[4] = {
10727 /* front, surround, clfe, side */
10728 0x03, 0x06, 0x05, 0x04
10729};
10730
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010731static hda_nid_t alc660_dac_nids[3] = {
10732 /* front, clfe, surround */
10733 0x03, 0x05, 0x06
10734};
10735
Kailang Yangdf694da2005-12-05 19:42:22 +010010736static hda_nid_t alc861_adc_nids[1] = {
10737 /* ADC0-2 */
10738 0x08,
10739};
10740
10741static struct hda_input_mux alc861_capture_source = {
10742 .num_items = 5,
10743 .items = {
10744 { "Mic", 0x0 },
10745 { "Front Mic", 0x3 },
10746 { "Line", 0x1 },
10747 { "CD", 0x4 },
10748 { "Mixer", 0x5 },
10749 },
10750};
10751
10752/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010753static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
10754 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010755{
10756 int i;
10757 hda_nid_t nid;
10758
10759 spec->multiout.dac_nids = spec->private_dac_nids;
10760 for (i = 0; i < cfg->line_outs; i++) {
10761 nid = cfg->line_out_pins[i];
10762 if (nid) {
10763 if (i >= ARRAY_SIZE(alc861_dac_nids))
10764 continue;
10765 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
10766 }
10767 }
10768 spec->multiout.num_dacs = cfg->line_outs;
10769 return 0;
10770}
10771
10772/* add playback controls from the parsed DAC table */
10773static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
10774 const struct auto_pin_cfg *cfg)
10775{
10776 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010777 static const char *chname[4] = {
10778 "Front", "Surround", NULL /*CLFE*/, "Side"
10779 };
Kailang Yangdf694da2005-12-05 19:42:22 +010010780 hda_nid_t nid;
10781 int i, idx, err;
10782
10783 for (i = 0; i < cfg->line_outs; i++) {
10784 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010785 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010010786 continue;
10787 if (nid == 0x05) {
10788 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010789 err = add_control(spec, ALC_CTL_BIND_MUTE,
10790 "Center Playback Switch",
10791 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
10792 HDA_OUTPUT));
10793 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010794 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010795 err = add_control(spec, ALC_CTL_BIND_MUTE,
10796 "LFE Playback Switch",
10797 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10798 HDA_OUTPUT));
10799 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010800 return err;
10801 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010802 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
10803 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010010804 if (nid == alc861_dac_nids[idx])
10805 break;
10806 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010807 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
10808 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10809 HDA_OUTPUT));
10810 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010811 return err;
10812 }
10813 }
10814 return 0;
10815}
10816
10817static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
10818{
10819 int err;
10820 hda_nid_t nid;
10821
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010822 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010010823 return 0;
10824
10825 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
10826 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010827 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10828 "Headphone Playback Switch",
10829 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10830 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010831 return err;
10832 spec->multiout.hp_nid = nid;
10833 }
10834 return 0;
10835}
10836
10837/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010838static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
10839 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010840{
Kailang Yangdf694da2005-12-05 19:42:22 +010010841 struct hda_input_mux *imux = &spec->private_imux;
10842 int i, err, idx, idx1;
10843
10844 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010845 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010846 case 0x0c:
10847 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010848 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010010849 break;
10850 case 0x0f:
10851 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010852 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010010853 break;
10854 case 0x0d:
10855 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010856 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010010857 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010858 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010010859 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010860 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010010861 break;
10862 case 0x11:
10863 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010864 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010010865 break;
10866 default:
10867 continue;
10868 }
10869
Takashi Iwai4a471b72005-12-07 13:56:29 +010010870 err = new_analog_input(spec, cfg->input_pins[i],
10871 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010010872 if (err < 0)
10873 return err;
10874
Takashi Iwai4a471b72005-12-07 13:56:29 +010010875 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010010876 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010877 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010010878 }
10879 return 0;
10880}
10881
10882static struct snd_kcontrol_new alc861_capture_mixer[] = {
10883 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10884 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10885
10886 {
10887 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10888 /* The multiple "Capture Source" controls confuse alsamixer
10889 * So call somewhat different..
10890 *FIXME: the controls appear in the "playback" view!
10891 */
10892 /* .name = "Capture Source", */
10893 .name = "Input Source",
10894 .count = 1,
10895 .info = alc_mux_enum_info,
10896 .get = alc_mux_enum_get,
10897 .put = alc_mux_enum_put,
10898 },
10899 { } /* end */
10900};
10901
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010902static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
10903 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010010904 int pin_type, int dac_idx)
10905{
10906 /* set as output */
10907
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010908 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10909 pin_type);
10910 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
10911 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010010912
10913}
10914
10915static void alc861_auto_init_multi_out(struct hda_codec *codec)
10916{
10917 struct alc_spec *spec = codec->spec;
10918 int i;
10919
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010920 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010010921 for (i = 0; i < spec->autocfg.line_outs; i++) {
10922 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010923 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010010924 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010925 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010926 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010010927 }
10928}
10929
10930static void alc861_auto_init_hp_out(struct hda_codec *codec)
10931{
10932 struct alc_spec *spec = codec->spec;
10933 hda_nid_t pin;
10934
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010935 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010936 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010937 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
10938 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010010939}
10940
10941static void alc861_auto_init_analog_input(struct hda_codec *codec)
10942{
10943 struct alc_spec *spec = codec->spec;
10944 int i;
10945
10946 for (i = 0; i < AUTO_PIN_LAST; i++) {
10947 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010948 if (nid >= 0x0c && nid <= 0x11) {
10949 snd_hda_codec_write(codec, nid, 0,
10950 AC_VERB_SET_PIN_WIDGET_CONTROL,
10951 i <= AUTO_PIN_FRONT_MIC ?
10952 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010010953 }
10954 }
10955}
10956
10957/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010958/* return 1 if successful, 0 if the proper config is not found,
10959 * or a negative error code
10960 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010961static int alc861_parse_auto_config(struct hda_codec *codec)
10962{
10963 struct alc_spec *spec = codec->spec;
10964 int err;
10965 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
10966
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010967 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10968 alc861_ignore);
10969 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010970 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010971 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010972 return 0; /* can't find valid BIOS pin config */
10973
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010974 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
10975 if (err < 0)
10976 return err;
10977 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
10978 if (err < 0)
10979 return err;
10980 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
10981 if (err < 0)
10982 return err;
10983 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
10984 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010985 return err;
10986
10987 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10988
10989 if (spec->autocfg.dig_out_pin)
10990 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
10991
10992 if (spec->kctl_alloc)
10993 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10994
10995 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
10996
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010997 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010998 spec->input_mux = &spec->private_imux;
10999
11000 spec->adc_nids = alc861_adc_nids;
11001 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
11002 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
11003 spec->num_mixers++;
11004
11005 return 1;
11006}
11007
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011008/* additional initialization for auto-configuration model */
11009static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011010{
Kailang Yangdf694da2005-12-05 19:42:22 +010011011 alc861_auto_init_multi_out(codec);
11012 alc861_auto_init_hp_out(codec);
11013 alc861_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011014}
11015
Takashi Iwaicb53c622007-08-10 17:21:45 +020011016#ifdef CONFIG_SND_HDA_POWER_SAVE
11017static struct hda_amp_list alc861_loopbacks[] = {
11018 { 0x15, HDA_INPUT, 0 },
11019 { 0x15, HDA_INPUT, 1 },
11020 { 0x15, HDA_INPUT, 2 },
11021 { 0x15, HDA_INPUT, 3 },
11022 { } /* end */
11023};
11024#endif
11025
Kailang Yangdf694da2005-12-05 19:42:22 +010011026
11027/*
11028 * configuration and preset
11029 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011030static const char *alc861_models[ALC861_MODEL_LAST] = {
11031 [ALC861_3ST] = "3stack",
11032 [ALC660_3ST] = "3stack-660",
11033 [ALC861_3ST_DIG] = "3stack-dig",
11034 [ALC861_6ST_DIG] = "6stack-dig",
11035 [ALC861_UNIWILL_M31] = "uniwill-m31",
11036 [ALC861_TOSHIBA] = "toshiba",
11037 [ALC861_ASUS] = "asus",
11038 [ALC861_ASUS_LAPTOP] = "asus-laptop",
11039 [ALC861_AUTO] = "auto",
11040};
11041
11042static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010011043 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011044 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11045 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11046 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011047 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020011048 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010011049 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020011050 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
11051 * Any other models that need this preset?
11052 */
11053 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020011054 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
11055 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011056 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
11057 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
11058 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
11059 /* FIXME: the below seems conflict */
11060 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
11061 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
11062 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010011063 {}
11064};
11065
11066static struct alc_config_preset alc861_presets[] = {
11067 [ALC861_3ST] = {
11068 .mixers = { alc861_3ST_mixer },
11069 .init_verbs = { alc861_threestack_init_verbs },
11070 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11071 .dac_nids = alc861_dac_nids,
11072 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11073 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011074 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011075 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11076 .adc_nids = alc861_adc_nids,
11077 .input_mux = &alc861_capture_source,
11078 },
11079 [ALC861_3ST_DIG] = {
11080 .mixers = { alc861_base_mixer },
11081 .init_verbs = { alc861_threestack_init_verbs },
11082 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11083 .dac_nids = alc861_dac_nids,
11084 .dig_out_nid = ALC861_DIGOUT_NID,
11085 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11086 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011087 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011088 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11089 .adc_nids = alc861_adc_nids,
11090 .input_mux = &alc861_capture_source,
11091 },
11092 [ALC861_6ST_DIG] = {
11093 .mixers = { alc861_base_mixer },
11094 .init_verbs = { alc861_base_init_verbs },
11095 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11096 .dac_nids = alc861_dac_nids,
11097 .dig_out_nid = ALC861_DIGOUT_NID,
11098 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
11099 .channel_mode = alc861_8ch_modes,
11100 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11101 .adc_nids = alc861_adc_nids,
11102 .input_mux = &alc861_capture_source,
11103 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011104 [ALC660_3ST] = {
11105 .mixers = { alc861_3ST_mixer },
11106 .init_verbs = { alc861_threestack_init_verbs },
11107 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
11108 .dac_nids = alc660_dac_nids,
11109 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11110 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011111 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011112 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11113 .adc_nids = alc861_adc_nids,
11114 .input_mux = &alc861_capture_source,
11115 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011116 [ALC861_UNIWILL_M31] = {
11117 .mixers = { alc861_uniwill_m31_mixer },
11118 .init_verbs = { alc861_uniwill_m31_init_verbs },
11119 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11120 .dac_nids = alc861_dac_nids,
11121 .dig_out_nid = ALC861_DIGOUT_NID,
11122 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
11123 .channel_mode = alc861_uniwill_m31_modes,
11124 .need_dac_fix = 1,
11125 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11126 .adc_nids = alc861_adc_nids,
11127 .input_mux = &alc861_capture_source,
11128 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011129 [ALC861_TOSHIBA] = {
11130 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011131 .init_verbs = { alc861_base_init_verbs,
11132 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011133 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11134 .dac_nids = alc861_dac_nids,
11135 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11136 .channel_mode = alc883_3ST_2ch_modes,
11137 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11138 .adc_nids = alc861_adc_nids,
11139 .input_mux = &alc861_capture_source,
11140 .unsol_event = alc861_toshiba_unsol_event,
11141 .init_hook = alc861_toshiba_automute,
11142 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011143 [ALC861_ASUS] = {
11144 .mixers = { alc861_asus_mixer },
11145 .init_verbs = { alc861_asus_init_verbs },
11146 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11147 .dac_nids = alc861_dac_nids,
11148 .dig_out_nid = ALC861_DIGOUT_NID,
11149 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
11150 .channel_mode = alc861_asus_modes,
11151 .need_dac_fix = 1,
11152 .hp_nid = 0x06,
11153 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11154 .adc_nids = alc861_adc_nids,
11155 .input_mux = &alc861_capture_source,
11156 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011157 [ALC861_ASUS_LAPTOP] = {
11158 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
11159 .init_verbs = { alc861_asus_init_verbs,
11160 alc861_asus_laptop_init_verbs },
11161 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11162 .dac_nids = alc861_dac_nids,
11163 .dig_out_nid = ALC861_DIGOUT_NID,
11164 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11165 .channel_mode = alc883_3ST_2ch_modes,
11166 .need_dac_fix = 1,
11167 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11168 .adc_nids = alc861_adc_nids,
11169 .input_mux = &alc861_capture_source,
11170 },
11171};
Kailang Yangdf694da2005-12-05 19:42:22 +010011172
11173
11174static int patch_alc861(struct hda_codec *codec)
11175{
11176 struct alc_spec *spec;
11177 int board_config;
11178 int err;
11179
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011180 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011181 if (spec == NULL)
11182 return -ENOMEM;
11183
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011184 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011185
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011186 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
11187 alc861_models,
11188 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011189
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011190 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011191 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
11192 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011193 board_config = ALC861_AUTO;
11194 }
11195
11196 if (board_config == ALC861_AUTO) {
11197 /* automatic parse from the BIOS config */
11198 err = alc861_parse_auto_config(codec);
11199 if (err < 0) {
11200 alc_free(codec);
11201 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011202 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011203 printk(KERN_INFO
11204 "hda_codec: Cannot set up configuration "
11205 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011206 board_config = ALC861_3ST_DIG;
11207 }
11208 }
11209
11210 if (board_config != ALC861_AUTO)
11211 setup_preset(spec, &alc861_presets[board_config]);
11212
11213 spec->stream_name_analog = "ALC861 Analog";
11214 spec->stream_analog_playback = &alc861_pcm_analog_playback;
11215 spec->stream_analog_capture = &alc861_pcm_analog_capture;
11216
11217 spec->stream_name_digital = "ALC861 Digital";
11218 spec->stream_digital_playback = &alc861_pcm_digital_playback;
11219 spec->stream_digital_capture = &alc861_pcm_digital_capture;
11220
11221 codec->patch_ops = alc_patch_ops;
11222 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011223 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011224#ifdef CONFIG_SND_HDA_POWER_SAVE
11225 if (!spec->loopback.amplist)
11226 spec->loopback.amplist = alc861_loopbacks;
11227#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011228
11229 return 0;
11230}
11231
11232/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011233 * ALC861-VD support
11234 *
11235 * Based on ALC882
11236 *
11237 * In addition, an independent DAC
11238 */
11239#define ALC861VD_DIGOUT_NID 0x06
11240
11241static hda_nid_t alc861vd_dac_nids[4] = {
11242 /* front, surr, clfe, side surr */
11243 0x02, 0x03, 0x04, 0x05
11244};
11245
11246/* dac_nids for ALC660vd are in a different order - according to
11247 * Realtek's driver.
11248 * This should probably tesult in a different mixer for 6stack models
11249 * of ALC660vd codecs, but for now there is only 3stack mixer
11250 * - and it is the same as in 861vd.
11251 * adc_nids in ALC660vd are (is) the same as in 861vd
11252 */
11253static hda_nid_t alc660vd_dac_nids[3] = {
11254 /* front, rear, clfe, rear_surr */
11255 0x02, 0x04, 0x03
11256};
11257
11258static hda_nid_t alc861vd_adc_nids[1] = {
11259 /* ADC0 */
11260 0x09,
11261};
11262
11263/* input MUX */
11264/* FIXME: should be a matrix-type input source selection */
11265static struct hda_input_mux alc861vd_capture_source = {
11266 .num_items = 4,
11267 .items = {
11268 { "Mic", 0x0 },
11269 { "Front Mic", 0x1 },
11270 { "Line", 0x2 },
11271 { "CD", 0x4 },
11272 },
11273};
11274
Kailang Yang272a5272007-05-14 11:00:38 +020011275static struct hda_input_mux alc861vd_dallas_capture_source = {
11276 .num_items = 3,
11277 .items = {
11278 { "Front Mic", 0x0 },
11279 { "ATAPI Mic", 0x1 },
11280 { "Line In", 0x5 },
11281 },
11282};
11283
Kailang Yangd1a991a2007-08-15 16:21:59 +020011284static struct hda_input_mux alc861vd_hp_capture_source = {
11285 .num_items = 2,
11286 .items = {
11287 { "Front Mic", 0x0 },
11288 { "ATAPI Mic", 0x1 },
11289 },
11290};
11291
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011292#define alc861vd_mux_enum_info alc_mux_enum_info
11293#define alc861vd_mux_enum_get alc_mux_enum_get
11294
11295static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
11296 struct snd_ctl_elem_value *ucontrol)
11297{
11298 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11299 struct alc_spec *spec = codec->spec;
11300 const struct hda_input_mux *imux = spec->input_mux;
11301 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
11302 static hda_nid_t capture_mixers[1] = { 0x22 };
11303 hda_nid_t nid = capture_mixers[adc_idx];
11304 unsigned int *cur_val = &spec->cur_mux[adc_idx];
11305 unsigned int i, idx;
11306
11307 idx = ucontrol->value.enumerated.item[0];
11308 if (idx >= imux->num_items)
11309 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011310 if (*cur_val == idx)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011311 return 0;
11312 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +020011313 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
11314 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
11315 imux->items[i].index,
11316 HDA_AMP_MUTE, v);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011317 }
11318 *cur_val = idx;
11319 return 1;
11320}
11321
11322/*
11323 * 2ch mode
11324 */
11325static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
11326 { 2, NULL }
11327};
11328
11329/*
11330 * 6ch mode
11331 */
11332static struct hda_verb alc861vd_6stack_ch6_init[] = {
11333 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11334 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11335 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11336 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11337 { } /* end */
11338};
11339
11340/*
11341 * 8ch mode
11342 */
11343static struct hda_verb alc861vd_6stack_ch8_init[] = {
11344 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11345 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11346 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11347 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11348 { } /* end */
11349};
11350
11351static struct hda_channel_mode alc861vd_6stack_modes[2] = {
11352 { 6, alc861vd_6stack_ch6_init },
11353 { 8, alc861vd_6stack_ch8_init },
11354};
11355
11356static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
11357 {
11358 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11359 .name = "Channel Mode",
11360 .info = alc_ch_mode_info,
11361 .get = alc_ch_mode_get,
11362 .put = alc_ch_mode_put,
11363 },
11364 { } /* end */
11365};
11366
11367static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
11368 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
11369 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
11370
11371 {
11372 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11373 /* The multiple "Capture Source" controls confuse alsamixer
11374 * So call somewhat different..
11375 *FIXME: the controls appear in the "playback" view!
11376 */
11377 /* .name = "Capture Source", */
11378 .name = "Input Source",
11379 .count = 1,
11380 .info = alc861vd_mux_enum_info,
11381 .get = alc861vd_mux_enum_get,
11382 .put = alc861vd_mux_enum_put,
11383 },
11384 { } /* end */
11385};
11386
11387/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
11388 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
11389 */
11390static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
11391 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11392 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11393
11394 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11395 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
11396
11397 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
11398 HDA_OUTPUT),
11399 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
11400 HDA_OUTPUT),
11401 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11402 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
11403
11404 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
11405 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
11406
11407 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11408
11409 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11410 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11411 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11412
11413 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11414 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11415 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11416
11417 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11418 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11419
11420 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11421 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11422
11423 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11424 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11425
11426 { } /* end */
11427};
11428
11429static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
11430 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11431 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11432
11433 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11434
11435 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11436 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11437 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11438
11439 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11440 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11441 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11442
11443 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11444 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11445
11446 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11447 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11448
11449 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11450 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11451
11452 { } /* end */
11453};
11454
Kailang Yangbdd148a2007-05-08 15:19:08 +020011455static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
11456 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11457 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
11458 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11459
11460 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11461
11462 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11463 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11464 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11465
11466 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11467 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11468 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11469
11470 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11471 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11472
11473 { } /* end */
11474};
11475
Kailang Yang272a5272007-05-14 11:00:38 +020011476/* Pin assignment: Front=0x14, HP = 0x15,
11477 * Front Mic=0x18, ATAPI Mic = 0x19, Line In = 0x1d
11478 */
11479static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
11480 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11481 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11482 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11483 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
11484 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11485 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11486 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11487 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11488 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT),
11489 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020011490 { } /* end */
11491};
11492
Kailang Yangd1a991a2007-08-15 16:21:59 +020011493/* Pin assignment: Speaker=0x14, Line-out = 0x15,
11494 * Front Mic=0x18, ATAPI Mic = 0x19,
11495 */
11496static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
11497 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11498 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11499 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11500 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
11501 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11502 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11503 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11504 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11505
11506 { } /* end */
11507};
11508
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011509/*
11510 * generic initialization of ADC, input mixers and output mixers
11511 */
11512static struct hda_verb alc861vd_volume_init_verbs[] = {
11513 /*
11514 * Unmute ADC0 and set the default input to mic-in
11515 */
11516 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11517 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11518
11519 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
11520 * the analog-loopback mixer widget
11521 */
11522 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011523 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11524 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11525 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11526 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11527 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011528
11529 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020011530 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011533 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011534
11535 /*
11536 * Set up output mixers (0x02 - 0x05)
11537 */
11538 /* set vol=0 to output mixers */
11539 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11540 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11541 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11542 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11543
11544 /* set up input amps for analog loopback */
11545 /* Amp Indices: DAC = 0, mixer = 1 */
11546 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11547 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11548 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11549 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11550 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11551 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11552 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11553 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11554
11555 { }
11556};
11557
11558/*
11559 * 3-stack pin configuration:
11560 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
11561 */
11562static struct hda_verb alc861vd_3stack_init_verbs[] = {
11563 /*
11564 * Set pin mode and muting
11565 */
11566 /* set front pin widgets 0x14 for output */
11567 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11568 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11569 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11570
11571 /* Mic (rear) pin: input vref at 80% */
11572 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11573 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11574 /* Front Mic pin: input vref at 80% */
11575 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11576 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11577 /* Line In pin: input */
11578 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11579 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11580 /* Line-2 In: Headphone output (output 0 - 0x0c) */
11581 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11582 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11583 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11584 /* CD pin widget for input */
11585 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11586
11587 { }
11588};
11589
11590/*
11591 * 6-stack pin configuration:
11592 */
11593static struct hda_verb alc861vd_6stack_init_verbs[] = {
11594 /*
11595 * Set pin mode and muting
11596 */
11597 /* set front pin widgets 0x14 for output */
11598 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11599 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11600 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11601
11602 /* Rear Pin: output 1 (0x0d) */
11603 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11604 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11605 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11606 /* CLFE Pin: output 2 (0x0e) */
11607 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11608 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11609 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
11610 /* Side Pin: output 3 (0x0f) */
11611 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11612 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11613 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
11614
11615 /* Mic (rear) pin: input vref at 80% */
11616 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11617 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11618 /* Front Mic pin: input vref at 80% */
11619 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11620 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11621 /* Line In pin: input */
11622 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11623 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11624 /* Line-2 In: Headphone output (output 0 - 0x0c) */
11625 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11626 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11627 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11628 /* CD pin widget for input */
11629 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11630
11631 { }
11632};
11633
Kailang Yangbdd148a2007-05-08 15:19:08 +020011634static struct hda_verb alc861vd_eapd_verbs[] = {
11635 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11636 { }
11637};
11638
11639static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
11640 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11641 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11642 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11643 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11644 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11645 {}
11646};
11647
11648/* toggle speaker-output according to the hp-jack state */
11649static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
11650{
11651 unsigned int present;
11652 unsigned char bits;
11653
11654 present = snd_hda_codec_read(codec, 0x1b, 0,
11655 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011656 bits = present ? HDA_AMP_MUTE : 0;
11657 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11658 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020011659}
11660
11661static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
11662{
11663 unsigned int present;
11664 unsigned char bits;
11665
11666 present = snd_hda_codec_read(codec, 0x18, 0,
11667 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011668 bits = present ? HDA_AMP_MUTE : 0;
11669 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
11670 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020011671}
11672
11673static void alc861vd_lenovo_automute(struct hda_codec *codec)
11674{
11675 alc861vd_lenovo_hp_automute(codec);
11676 alc861vd_lenovo_mic_automute(codec);
11677}
11678
11679static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
11680 unsigned int res)
11681{
11682 switch (res >> 26) {
11683 case ALC880_HP_EVENT:
11684 alc861vd_lenovo_hp_automute(codec);
11685 break;
11686 case ALC880_MIC_EVENT:
11687 alc861vd_lenovo_mic_automute(codec);
11688 break;
11689 }
11690}
11691
Kailang Yang272a5272007-05-14 11:00:38 +020011692static struct hda_verb alc861vd_dallas_verbs[] = {
11693 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11694 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11695 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11696 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11697
11698 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11699 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11700 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11701 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11702 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11703 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11704 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11705 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11706
11707 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11708 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11709 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11710 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11711 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11712 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11713 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11714 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11715
11716 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11717 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11718 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11719 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11720 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11721 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11722 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11723 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11724
11725 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11726 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11727 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11728 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11729
11730 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11731 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11732 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11733
11734 { } /* end */
11735};
11736
11737/* toggle speaker-output according to the hp-jack state */
11738static void alc861vd_dallas_automute(struct hda_codec *codec)
11739{
11740 unsigned int present;
11741
11742 present = snd_hda_codec_read(codec, 0x15, 0,
11743 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011744 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11745 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020011746}
11747
11748static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
11749{
11750 if ((res >> 26) == ALC880_HP_EVENT)
11751 alc861vd_dallas_automute(codec);
11752}
11753
Takashi Iwaicb53c622007-08-10 17:21:45 +020011754#ifdef CONFIG_SND_HDA_POWER_SAVE
11755#define alc861vd_loopbacks alc880_loopbacks
11756#endif
11757
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011758/* pcm configuration: identiacal with ALC880 */
11759#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
11760#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
11761#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
11762#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
11763
11764/*
11765 * configuration and preset
11766 */
11767static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
11768 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011769 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011770 [ALC861VD_3ST] = "3stack",
11771 [ALC861VD_3ST_DIG] = "3stack-digout",
11772 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020011773 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020011774 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011775 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011776 [ALC861VD_AUTO] = "auto",
11777};
11778
11779static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011780 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
11781 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010011782 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011783 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020011784 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011785 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011786 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020011787 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020011788 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020011789 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Takashi Iwai39c5d412007-08-15 16:24:17 +020011790 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011791 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
11792 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020011793 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011794 {}
11795};
11796
11797static struct alc_config_preset alc861vd_presets[] = {
11798 [ALC660VD_3ST] = {
11799 .mixers = { alc861vd_3st_mixer },
11800 .init_verbs = { alc861vd_volume_init_verbs,
11801 alc861vd_3stack_init_verbs },
11802 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
11803 .dac_nids = alc660vd_dac_nids,
11804 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
11805 .adc_nids = alc861vd_adc_nids,
11806 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11807 .channel_mode = alc861vd_3stack_2ch_modes,
11808 .input_mux = &alc861vd_capture_source,
11809 },
Mike Crash6963f842007-06-25 12:12:51 +020011810 [ALC660VD_3ST_DIG] = {
11811 .mixers = { alc861vd_3st_mixer },
11812 .init_verbs = { alc861vd_volume_init_verbs,
11813 alc861vd_3stack_init_verbs },
11814 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
11815 .dac_nids = alc660vd_dac_nids,
11816 .dig_out_nid = ALC861VD_DIGOUT_NID,
11817 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
11818 .adc_nids = alc861vd_adc_nids,
11819 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11820 .channel_mode = alc861vd_3stack_2ch_modes,
11821 .input_mux = &alc861vd_capture_source,
11822 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011823 [ALC861VD_3ST] = {
11824 .mixers = { alc861vd_3st_mixer },
11825 .init_verbs = { alc861vd_volume_init_verbs,
11826 alc861vd_3stack_init_verbs },
11827 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
11828 .dac_nids = alc861vd_dac_nids,
11829 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11830 .channel_mode = alc861vd_3stack_2ch_modes,
11831 .input_mux = &alc861vd_capture_source,
11832 },
11833 [ALC861VD_3ST_DIG] = {
11834 .mixers = { alc861vd_3st_mixer },
11835 .init_verbs = { alc861vd_volume_init_verbs,
11836 alc861vd_3stack_init_verbs },
11837 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
11838 .dac_nids = alc861vd_dac_nids,
11839 .dig_out_nid = ALC861VD_DIGOUT_NID,
11840 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11841 .channel_mode = alc861vd_3stack_2ch_modes,
11842 .input_mux = &alc861vd_capture_source,
11843 },
11844 [ALC861VD_6ST_DIG] = {
11845 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
11846 .init_verbs = { alc861vd_volume_init_verbs,
11847 alc861vd_6stack_init_verbs },
11848 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
11849 .dac_nids = alc861vd_dac_nids,
11850 .dig_out_nid = ALC861VD_DIGOUT_NID,
11851 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
11852 .channel_mode = alc861vd_6stack_modes,
11853 .input_mux = &alc861vd_capture_source,
11854 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020011855 [ALC861VD_LENOVO] = {
11856 .mixers = { alc861vd_lenovo_mixer },
11857 .init_verbs = { alc861vd_volume_init_verbs,
11858 alc861vd_3stack_init_verbs,
11859 alc861vd_eapd_verbs,
11860 alc861vd_lenovo_unsol_verbs },
11861 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
11862 .dac_nids = alc660vd_dac_nids,
11863 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
11864 .adc_nids = alc861vd_adc_nids,
11865 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11866 .channel_mode = alc861vd_3stack_2ch_modes,
11867 .input_mux = &alc861vd_capture_source,
11868 .unsol_event = alc861vd_lenovo_unsol_event,
11869 .init_hook = alc861vd_lenovo_automute,
11870 },
Kailang Yang272a5272007-05-14 11:00:38 +020011871 [ALC861VD_DALLAS] = {
11872 .mixers = { alc861vd_dallas_mixer },
11873 .init_verbs = { alc861vd_dallas_verbs },
11874 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
11875 .dac_nids = alc861vd_dac_nids,
11876 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
11877 .adc_nids = alc861vd_adc_nids,
11878 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11879 .channel_mode = alc861vd_3stack_2ch_modes,
11880 .input_mux = &alc861vd_dallas_capture_source,
11881 .unsol_event = alc861vd_dallas_unsol_event,
11882 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011883 },
11884 [ALC861VD_HP] = {
11885 .mixers = { alc861vd_hp_mixer },
11886 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
11887 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
11888 .dac_nids = alc861vd_dac_nids,
11889 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
11890 .dig_out_nid = ALC861VD_DIGOUT_NID,
11891 .adc_nids = alc861vd_adc_nids,
11892 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
11893 .channel_mode = alc861vd_3stack_2ch_modes,
11894 .input_mux = &alc861vd_hp_capture_source,
11895 .unsol_event = alc861vd_dallas_unsol_event,
11896 .init_hook = alc861vd_dallas_automute,
11897 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011898};
11899
11900/*
11901 * BIOS auto configuration
11902 */
11903static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
11904 hda_nid_t nid, int pin_type, int dac_idx)
11905{
11906 /* set as output */
11907 snd_hda_codec_write(codec, nid, 0,
11908 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
11909 snd_hda_codec_write(codec, nid, 0,
11910 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
11911}
11912
11913static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
11914{
11915 struct alc_spec *spec = codec->spec;
11916 int i;
11917
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011918 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011919 for (i = 0; i <= HDA_SIDE; i++) {
11920 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011921 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011922 if (nid)
11923 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011924 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011925 }
11926}
11927
11928
11929static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
11930{
11931 struct alc_spec *spec = codec->spec;
11932 hda_nid_t pin;
11933
11934 pin = spec->autocfg.hp_pins[0];
11935 if (pin) /* connect to front and use dac 0 */
11936 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
11937}
11938
11939#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
11940#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
11941
11942static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
11943{
11944 struct alc_spec *spec = codec->spec;
11945 int i;
11946
11947 for (i = 0; i < AUTO_PIN_LAST; i++) {
11948 hda_nid_t nid = spec->autocfg.input_pins[i];
11949 if (alc861vd_is_input_pin(nid)) {
11950 snd_hda_codec_write(codec, nid, 0,
11951 AC_VERB_SET_PIN_WIDGET_CONTROL,
11952 i <= AUTO_PIN_FRONT_MIC ?
11953 PIN_VREF80 : PIN_IN);
11954 if (nid != ALC861VD_PIN_CD_NID)
11955 snd_hda_codec_write(codec, nid, 0,
11956 AC_VERB_SET_AMP_GAIN_MUTE,
11957 AMP_OUT_MUTE);
11958 }
11959 }
11960}
11961
11962#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
11963#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
11964
11965/* add playback controls from the parsed DAC table */
11966/* Based on ALC880 version. But ALC861VD has separate,
11967 * different NIDs for mute/unmute switch and volume control */
11968static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
11969 const struct auto_pin_cfg *cfg)
11970{
11971 char name[32];
11972 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
11973 hda_nid_t nid_v, nid_s;
11974 int i, err;
11975
11976 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011977 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011978 continue;
11979 nid_v = alc861vd_idx_to_mixer_vol(
11980 alc880_dac_to_idx(
11981 spec->multiout.dac_nids[i]));
11982 nid_s = alc861vd_idx_to_mixer_switch(
11983 alc880_dac_to_idx(
11984 spec->multiout.dac_nids[i]));
11985
11986 if (i == 2) {
11987 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011988 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11989 "Center Playback Volume",
11990 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
11991 HDA_OUTPUT));
11992 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011993 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011994 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11995 "LFE Playback Volume",
11996 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
11997 HDA_OUTPUT));
11998 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011999 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012000 err = add_control(spec, ALC_CTL_BIND_MUTE,
12001 "Center Playback Switch",
12002 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12003 HDA_INPUT));
12004 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012005 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012006 err = add_control(spec, ALC_CTL_BIND_MUTE,
12007 "LFE Playback Switch",
12008 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12009 HDA_INPUT));
12010 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012011 return err;
12012 } else {
12013 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012014 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12015 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
12016 HDA_OUTPUT));
12017 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012018 return err;
12019 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012020 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012021 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012022 HDA_INPUT));
12023 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012024 return err;
12025 }
12026 }
12027 return 0;
12028}
12029
12030/* add playback controls for speaker and HP outputs */
12031/* Based on ALC880 version. But ALC861VD has separate,
12032 * different NIDs for mute/unmute switch and volume control */
12033static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
12034 hda_nid_t pin, const char *pfx)
12035{
12036 hda_nid_t nid_v, nid_s;
12037 int err;
12038 char name[32];
12039
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012040 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012041 return 0;
12042
12043 if (alc880_is_fixed_pin(pin)) {
12044 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12045 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012046 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012047 spec->multiout.hp_nid = nid_v;
12048 else
12049 spec->multiout.extra_out_nid[0] = nid_v;
12050 /* control HP volume/switch on the output mixer amp */
12051 nid_v = alc861vd_idx_to_mixer_vol(
12052 alc880_fixed_pin_idx(pin));
12053 nid_s = alc861vd_idx_to_mixer_switch(
12054 alc880_fixed_pin_idx(pin));
12055
12056 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012057 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12058 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
12059 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012060 return err;
12061 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012062 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12063 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
12064 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012065 return err;
12066 } else if (alc880_is_multi_pin(pin)) {
12067 /* set manual connection */
12068 /* we have only a switch on HP-out PIN */
12069 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012070 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12071 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12072 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012073 return err;
12074 }
12075 return 0;
12076}
12077
12078/* parse the BIOS configuration and set up the alc_spec
12079 * return 1 if successful, 0 if the proper config is not found,
12080 * or a negative error code
12081 * Based on ALC880 version - had to change it to override
12082 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
12083static int alc861vd_parse_auto_config(struct hda_codec *codec)
12084{
12085 struct alc_spec *spec = codec->spec;
12086 int err;
12087 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
12088
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012089 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12090 alc861vd_ignore);
12091 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012092 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012093 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012094 return 0; /* can't find valid BIOS pin config */
12095
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012096 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12097 if (err < 0)
12098 return err;
12099 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
12100 if (err < 0)
12101 return err;
12102 err = alc861vd_auto_create_extra_out(spec,
12103 spec->autocfg.speaker_pins[0],
12104 "Speaker");
12105 if (err < 0)
12106 return err;
12107 err = alc861vd_auto_create_extra_out(spec,
12108 spec->autocfg.hp_pins[0],
12109 "Headphone");
12110 if (err < 0)
12111 return err;
12112 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
12113 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012114 return err;
12115
12116 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12117
12118 if (spec->autocfg.dig_out_pin)
12119 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
12120
12121 if (spec->kctl_alloc)
12122 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12123
12124 spec->init_verbs[spec->num_init_verbs++]
12125 = alc861vd_volume_init_verbs;
12126
12127 spec->num_mux_defs = 1;
12128 spec->input_mux = &spec->private_imux;
12129
Takashi Iwai776e1842007-08-29 15:07:11 +020012130 err = alc_auto_add_mic_boost(codec);
12131 if (err < 0)
12132 return err;
12133
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012134 return 1;
12135}
12136
12137/* additional initialization for auto-configuration model */
12138static void alc861vd_auto_init(struct hda_codec *codec)
12139{
12140 alc861vd_auto_init_multi_out(codec);
12141 alc861vd_auto_init_hp_out(codec);
12142 alc861vd_auto_init_analog_input(codec);
12143}
12144
12145static int patch_alc861vd(struct hda_codec *codec)
12146{
12147 struct alc_spec *spec;
12148 int err, board_config;
12149
12150 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12151 if (spec == NULL)
12152 return -ENOMEM;
12153
12154 codec->spec = spec;
12155
12156 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
12157 alc861vd_models,
12158 alc861vd_cfg_tbl);
12159
12160 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
12161 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
12162 "ALC861VD, trying auto-probe from BIOS...\n");
12163 board_config = ALC861VD_AUTO;
12164 }
12165
12166 if (board_config == ALC861VD_AUTO) {
12167 /* automatic parse from the BIOS config */
12168 err = alc861vd_parse_auto_config(codec);
12169 if (err < 0) {
12170 alc_free(codec);
12171 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012172 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012173 printk(KERN_INFO
12174 "hda_codec: Cannot set up configuration "
12175 "from BIOS. Using base mode...\n");
12176 board_config = ALC861VD_3ST;
12177 }
12178 }
12179
12180 if (board_config != ALC861VD_AUTO)
12181 setup_preset(spec, &alc861vd_presets[board_config]);
12182
12183 spec->stream_name_analog = "ALC861VD Analog";
12184 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
12185 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
12186
12187 spec->stream_name_digital = "ALC861VD Digital";
12188 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
12189 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
12190
12191 spec->adc_nids = alc861vd_adc_nids;
12192 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
12193
12194 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
12195 spec->num_mixers++;
12196
12197 codec->patch_ops = alc_patch_ops;
12198
12199 if (board_config == ALC861VD_AUTO)
12200 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012201#ifdef CONFIG_SND_HDA_POWER_SAVE
12202 if (!spec->loopback.amplist)
12203 spec->loopback.amplist = alc861vd_loopbacks;
12204#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012205
12206 return 0;
12207}
12208
12209/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012210 * ALC662 support
12211 *
12212 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
12213 * configuration. Each pin widget can choose any input DACs and a mixer.
12214 * Each ADC is connected from a mixer of all inputs. This makes possible
12215 * 6-channel independent captures.
12216 *
12217 * In addition, an independent DAC for the multi-playback (not used in this
12218 * driver yet).
12219 */
12220#define ALC662_DIGOUT_NID 0x06
12221#define ALC662_DIGIN_NID 0x0a
12222
12223static hda_nid_t alc662_dac_nids[4] = {
12224 /* front, rear, clfe, rear_surr */
12225 0x02, 0x03, 0x04
12226};
12227
12228static hda_nid_t alc662_adc_nids[1] = {
12229 /* ADC1-2 */
12230 0x09,
12231};
12232/* input MUX */
12233/* FIXME: should be a matrix-type input source selection */
12234
12235static struct hda_input_mux alc662_capture_source = {
12236 .num_items = 4,
12237 .items = {
12238 { "Mic", 0x0 },
12239 { "Front Mic", 0x1 },
12240 { "Line", 0x2 },
12241 { "CD", 0x4 },
12242 },
12243};
12244
12245static struct hda_input_mux alc662_lenovo_101e_capture_source = {
12246 .num_items = 2,
12247 .items = {
12248 { "Mic", 0x1 },
12249 { "Line", 0x2 },
12250 },
12251};
Kailang Yang291702f2007-10-16 14:28:03 +020012252
12253static struct hda_input_mux alc662_eeepc_capture_source = {
12254 .num_items = 2,
12255 .items = {
12256 { "i-Mic", 0x1 },
12257 { "e-Mic", 0x0 },
12258 },
12259};
12260
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012261#define alc662_mux_enum_info alc_mux_enum_info
12262#define alc662_mux_enum_get alc_mux_enum_get
12263
12264static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
12265 struct snd_ctl_elem_value *ucontrol)
12266{
12267 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12268 struct alc_spec *spec = codec->spec;
12269 const struct hda_input_mux *imux = spec->input_mux;
12270 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Kailang Yangd1a991a2007-08-15 16:21:59 +020012271 static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012272 hda_nid_t nid = capture_mixers[adc_idx];
12273 unsigned int *cur_val = &spec->cur_mux[adc_idx];
12274 unsigned int i, idx;
12275
12276 idx = ucontrol->value.enumerated.item[0];
12277 if (idx >= imux->num_items)
12278 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +020012279 if (*cur_val == idx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012280 return 0;
12281 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +020012282 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
12283 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
12284 imux->items[i].index,
12285 HDA_AMP_MUTE, v);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012286 }
12287 *cur_val = idx;
12288 return 1;
12289}
12290/*
12291 * 2ch mode
12292 */
12293static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
12294 { 2, NULL }
12295};
12296
12297/*
12298 * 2ch mode
12299 */
12300static struct hda_verb alc662_3ST_ch2_init[] = {
12301 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
12302 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12303 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
12304 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12305 { } /* end */
12306};
12307
12308/*
12309 * 6ch mode
12310 */
12311static struct hda_verb alc662_3ST_ch6_init[] = {
12312 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12313 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12314 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
12315 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12316 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12317 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
12318 { } /* end */
12319};
12320
12321static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
12322 { 2, alc662_3ST_ch2_init },
12323 { 6, alc662_3ST_ch6_init },
12324};
12325
12326/*
12327 * 2ch mode
12328 */
12329static struct hda_verb alc662_sixstack_ch6_init[] = {
12330 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12331 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12332 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12333 { } /* end */
12334};
12335
12336/*
12337 * 6ch mode
12338 */
12339static struct hda_verb alc662_sixstack_ch8_init[] = {
12340 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12341 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12342 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12343 { } /* end */
12344};
12345
12346static struct hda_channel_mode alc662_5stack_modes[2] = {
12347 { 2, alc662_sixstack_ch6_init },
12348 { 6, alc662_sixstack_ch8_init },
12349};
12350
12351/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12352 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12353 */
12354
12355static struct snd_kcontrol_new alc662_base_mixer[] = {
12356 /* output mixer control */
12357 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12358 HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
12359 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12360 HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12361 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12362 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12363 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12364 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12365 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12366
12367 /*Input mixer control */
12368 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
12369 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
12370 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
12371 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
12372 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
12373 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
12374 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
12375 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012376 { } /* end */
12377};
12378
12379static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
12380 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12381 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12382 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12383 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12384 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12385 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12386 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12387 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12388 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12389 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12390 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12391 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12392 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012393 { } /* end */
12394};
12395
12396static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
12397 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12398 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12399 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12400 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12401 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12402 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12403 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12404 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12405 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12406 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12407 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12408 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12409 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12410 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12411 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12412 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12413 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12414 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12415 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012416 { } /* end */
12417};
12418
12419static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
12420 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12421 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12422 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12423 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT),
12424 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12425 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12426 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12427 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12428 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012429 { } /* end */
12430};
12431
Kailang Yang291702f2007-10-16 14:28:03 +020012432static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
12433 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12434
12435 HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12436 HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12437
12438 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
12439 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12440 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12441
12442 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
12443 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12444 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12445 { } /* end */
12446};
12447
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012448static struct snd_kcontrol_new alc662_chmode_mixer[] = {
12449 {
12450 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12451 .name = "Channel Mode",
12452 .info = alc_ch_mode_info,
12453 .get = alc_ch_mode_get,
12454 .put = alc_ch_mode_put,
12455 },
12456 { } /* end */
12457};
12458
12459static struct hda_verb alc662_init_verbs[] = {
12460 /* ADC: mute amp left and right */
12461 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12462 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12463 /* Front mixer: unmute input/output amp left and right (volume = 0) */
12464
Takashi Iwaicb53c622007-08-10 17:21:45 +020012465 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12466 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12467 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12468 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12469 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012470
Kailang Yangb60dd392007-09-20 12:50:29 +020012471 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12472 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12473 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12474 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12475 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12476 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012477
12478 /* Front Pin: output 0 (0x0c) */
12479 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12480 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12481
12482 /* Rear Pin: output 1 (0x0d) */
12483 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12484 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12485
12486 /* CLFE Pin: output 2 (0x0e) */
12487 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12488 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12489
12490 /* Mic (rear) pin: input vref at 80% */
12491 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12492 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12493 /* Front Mic pin: input vref at 80% */
12494 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12495 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12496 /* Line In pin: input */
12497 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12498 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12499 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12500 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12501 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12502 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12503 /* CD pin widget for input */
12504 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12505
12506 /* FIXME: use matrix-type input source selection */
12507 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12508 /* Input mixer */
12509 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12510 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12511 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12512 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020012513
12514 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12515 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12516 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12517 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012518 { }
12519};
12520
12521static struct hda_verb alc662_sue_init_verbs[] = {
12522 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
12523 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020012524 {}
12525};
12526
12527static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
12528 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12529 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12530 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012531};
12532
12533/*
12534 * generic initialization of ADC, input mixers and output mixers
12535 */
12536static struct hda_verb alc662_auto_init_verbs[] = {
12537 /*
12538 * Unmute ADC and set the default input to mic-in
12539 */
12540 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12541 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12542
12543 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
12544 * mixer widget
12545 * Note: PASD motherboards uses the Line In 2 as the input for front
12546 * panel mic (mic 2)
12547 */
12548 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012549 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12550 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12551 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12552 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12553 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012554
12555 /*
12556 * Set up output mixers (0x0c - 0x0f)
12557 */
12558 /* set vol=0 to output mixers */
12559 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12560 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12561 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12562
12563 /* set up input amps for analog loopback */
12564 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020012565 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12566 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12567 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12568 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12569 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12570 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012571
12572
12573 /* FIXME: use matrix-type input source selection */
12574 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12575 /* Input mixer */
12576 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020012577 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012578 { }
12579};
12580
12581/* capture mixer elements */
12582static struct snd_kcontrol_new alc662_capture_mixer[] = {
12583 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
12584 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
12585 {
12586 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12587 /* The multiple "Capture Source" controls confuse alsamixer
12588 * So call somewhat different..
12589 * FIXME: the controls appear in the "playback" view!
12590 */
12591 /* .name = "Capture Source", */
12592 .name = "Input Source",
12593 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010012594 .info = alc662_mux_enum_info,
12595 .get = alc662_mux_enum_get,
12596 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012597 },
12598 { } /* end */
12599};
12600
12601static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
12602{
12603 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012604 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012605
12606 present = snd_hda_codec_read(codec, 0x14, 0,
12607 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012608 bits = present ? HDA_AMP_MUTE : 0;
12609 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12610 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012611}
12612
12613static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
12614{
12615 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012616 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012617
12618 present = snd_hda_codec_read(codec, 0x1b, 0,
12619 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012620 bits = present ? HDA_AMP_MUTE : 0;
12621 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12622 HDA_AMP_MUTE, bits);
12623 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12624 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012625}
12626
12627static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
12628 unsigned int res)
12629{
12630 if ((res >> 26) == ALC880_HP_EVENT)
12631 alc662_lenovo_101e_all_automute(codec);
12632 if ((res >> 26) == ALC880_FRONT_EVENT)
12633 alc662_lenovo_101e_ispeaker_automute(codec);
12634}
12635
Kailang Yang291702f2007-10-16 14:28:03 +020012636static void alc662_eeepc_mic_automute(struct hda_codec *codec)
12637{
12638 unsigned int present;
12639
12640 present = snd_hda_codec_read(codec, 0x18, 0,
12641 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12642 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12643 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12644 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12645 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12646 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12647 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12648 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12649 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12650}
12651
12652/* unsolicited event for HP jack sensing */
12653static void alc662_eeepc_unsol_event(struct hda_codec *codec,
12654 unsigned int res)
12655{
12656 if ((res >> 26) == ALC880_HP_EVENT)
12657 alc262_hippo1_automute( codec );
12658
12659 if ((res >> 26) == ALC880_MIC_EVENT)
12660 alc662_eeepc_mic_automute(codec);
12661}
12662
12663static void alc662_eeepc_inithook(struct hda_codec *codec)
12664{
12665 alc262_hippo1_automute( codec );
12666 alc662_eeepc_mic_automute(codec);
12667}
12668
Takashi Iwaicb53c622007-08-10 17:21:45 +020012669#ifdef CONFIG_SND_HDA_POWER_SAVE
12670#define alc662_loopbacks alc880_loopbacks
12671#endif
12672
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012673
12674/* pcm configuration: identiacal with ALC880 */
12675#define alc662_pcm_analog_playback alc880_pcm_analog_playback
12676#define alc662_pcm_analog_capture alc880_pcm_analog_capture
12677#define alc662_pcm_digital_playback alc880_pcm_digital_playback
12678#define alc662_pcm_digital_capture alc880_pcm_digital_capture
12679
12680/*
12681 * configuration and preset
12682 */
12683static const char *alc662_models[ALC662_MODEL_LAST] = {
12684 [ALC662_3ST_2ch_DIG] = "3stack-dig",
12685 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
12686 [ALC662_3ST_6ch] = "3stack-6ch",
12687 [ALC662_5ST_DIG] = "6stack-dig",
12688 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020012689 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012690 [ALC662_AUTO] = "auto",
12691};
12692
12693static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020012694 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012695 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012696 {}
12697};
12698
12699static struct alc_config_preset alc662_presets[] = {
12700 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020012701 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012702 .init_verbs = { alc662_init_verbs },
12703 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
12704 .dac_nids = alc662_dac_nids,
12705 .dig_out_nid = ALC662_DIGOUT_NID,
12706 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
12707 .adc_nids = alc662_adc_nids,
12708 .dig_in_nid = ALC662_DIGIN_NID,
12709 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
12710 .channel_mode = alc662_3ST_2ch_modes,
12711 .input_mux = &alc662_capture_source,
12712 },
12713 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020012714 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
12715 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012716 .init_verbs = { alc662_init_verbs },
12717 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
12718 .dac_nids = alc662_dac_nids,
12719 .dig_out_nid = ALC662_DIGOUT_NID,
12720 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
12721 .adc_nids = alc662_adc_nids,
12722 .dig_in_nid = ALC662_DIGIN_NID,
12723 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
12724 .channel_mode = alc662_3ST_6ch_modes,
12725 .need_dac_fix = 1,
12726 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012727 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012728 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020012729 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
12730 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012731 .init_verbs = { alc662_init_verbs },
12732 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
12733 .dac_nids = alc662_dac_nids,
12734 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
12735 .adc_nids = alc662_adc_nids,
12736 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
12737 .channel_mode = alc662_3ST_6ch_modes,
12738 .need_dac_fix = 1,
12739 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012740 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012741 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020012742 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
12743 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012744 .init_verbs = { alc662_init_verbs },
12745 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
12746 .dac_nids = alc662_dac_nids,
12747 .dig_out_nid = ALC662_DIGOUT_NID,
12748 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
12749 .adc_nids = alc662_adc_nids,
12750 .dig_in_nid = ALC662_DIGIN_NID,
12751 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
12752 .channel_mode = alc662_5stack_modes,
12753 .input_mux = &alc662_capture_source,
12754 },
12755 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020012756 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012757 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
12758 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
12759 .dac_nids = alc662_dac_nids,
12760 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
12761 .adc_nids = alc662_adc_nids,
12762 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
12763 .channel_mode = alc662_3ST_2ch_modes,
12764 .input_mux = &alc662_lenovo_101e_capture_source,
12765 .unsol_event = alc662_lenovo_101e_unsol_event,
12766 .init_hook = alc662_lenovo_101e_all_automute,
12767 },
Kailang Yang291702f2007-10-16 14:28:03 +020012768 [ALC662_ASUS_EEEPC_P701] = {
12769 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
12770 .init_verbs = { alc662_init_verbs,
12771 alc662_eeepc_sue_init_verbs },
12772 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
12773 .dac_nids = alc662_dac_nids,
12774 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
12775 .adc_nids = alc662_adc_nids,
12776 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
12777 .channel_mode = alc662_3ST_2ch_modes,
12778 .input_mux = &alc662_eeepc_capture_source,
12779 .unsol_event = alc662_eeepc_unsol_event,
12780 .init_hook = alc662_eeepc_inithook,
12781 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012782
12783};
12784
12785
12786/*
12787 * BIOS auto configuration
12788 */
12789
12790/* add playback controls from the parsed DAC table */
12791static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
12792 const struct auto_pin_cfg *cfg)
12793{
12794 char name[32];
12795 static const char *chname[4] = {
12796 "Front", "Surround", NULL /*CLFE*/, "Side"
12797 };
12798 hda_nid_t nid;
12799 int i, err;
12800
12801 for (i = 0; i < cfg->line_outs; i++) {
12802 if (!spec->multiout.dac_nids[i])
12803 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020012804 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012805 if (i == 2) {
12806 /* Center/LFE */
12807 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12808 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012809 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
12810 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012811 if (err < 0)
12812 return err;
12813 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12814 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012815 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12816 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012817 if (err < 0)
12818 return err;
12819 err = add_control(spec, ALC_CTL_BIND_MUTE,
12820 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012821 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
12822 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012823 if (err < 0)
12824 return err;
12825 err = add_control(spec, ALC_CTL_BIND_MUTE,
12826 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012827 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
12828 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012829 if (err < 0)
12830 return err;
12831 } else {
12832 sprintf(name, "%s Playback Volume", chname[i]);
12833 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012834 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12835 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012836 if (err < 0)
12837 return err;
12838 sprintf(name, "%s Playback Switch", chname[i]);
12839 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012840 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
12841 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012842 if (err < 0)
12843 return err;
12844 }
12845 }
12846 return 0;
12847}
12848
12849/* add playback controls for speaker and HP outputs */
12850static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
12851 const char *pfx)
12852{
12853 hda_nid_t nid;
12854 int err;
12855 char name[32];
12856
12857 if (!pin)
12858 return 0;
12859
12860 if (alc880_is_fixed_pin(pin)) {
12861 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12862 /* printk("DAC nid=%x\n",nid); */
12863 /* specify the DAC as the extra output */
12864 if (!spec->multiout.hp_nid)
12865 spec->multiout.hp_nid = nid;
12866 else
12867 spec->multiout.extra_out_nid[0] = nid;
12868 /* control HP volume/switch on the output mixer amp */
12869 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12870 sprintf(name, "%s Playback Volume", pfx);
12871 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12872 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12873 if (err < 0)
12874 return err;
12875 sprintf(name, "%s Playback Switch", pfx);
12876 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12877 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
12878 if (err < 0)
12879 return err;
12880 } else if (alc880_is_multi_pin(pin)) {
12881 /* set manual connection */
12882 /* we have only a switch on HP-out PIN */
12883 sprintf(name, "%s Playback Switch", pfx);
12884 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12885 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12886 if (err < 0)
12887 return err;
12888 }
12889 return 0;
12890}
12891
12892/* create playback/capture controls for input pins */
12893static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
12894 const struct auto_pin_cfg *cfg)
12895{
12896 struct hda_input_mux *imux = &spec->private_imux;
12897 int i, err, idx;
12898
12899 for (i = 0; i < AUTO_PIN_LAST; i++) {
12900 if (alc880_is_input_pin(cfg->input_pins[i])) {
12901 idx = alc880_input_pin_idx(cfg->input_pins[i]);
12902 err = new_analog_input(spec, cfg->input_pins[i],
12903 auto_pin_cfg_labels[i],
12904 idx, 0x0b);
12905 if (err < 0)
12906 return err;
12907 imux->items[imux->num_items].label =
12908 auto_pin_cfg_labels[i];
12909 imux->items[imux->num_items].index =
12910 alc880_input_pin_idx(cfg->input_pins[i]);
12911 imux->num_items++;
12912 }
12913 }
12914 return 0;
12915}
12916
12917static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
12918 hda_nid_t nid, int pin_type,
12919 int dac_idx)
12920{
12921 /* set as output */
12922 snd_hda_codec_write(codec, nid, 0,
12923 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
12924 snd_hda_codec_write(codec, nid, 0,
12925 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
12926 /* need the manual connection? */
12927 if (alc880_is_multi_pin(nid)) {
12928 struct alc_spec *spec = codec->spec;
12929 int idx = alc880_multi_pin_idx(nid);
12930 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
12931 AC_VERB_SET_CONNECT_SEL,
12932 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
12933 }
12934}
12935
12936static void alc662_auto_init_multi_out(struct hda_codec *codec)
12937{
12938 struct alc_spec *spec = codec->spec;
12939 int i;
12940
12941 for (i = 0; i <= HDA_SIDE; i++) {
12942 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012943 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012944 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012945 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012946 i);
12947 }
12948}
12949
12950static void alc662_auto_init_hp_out(struct hda_codec *codec)
12951{
12952 struct alc_spec *spec = codec->spec;
12953 hda_nid_t pin;
12954
12955 pin = spec->autocfg.hp_pins[0];
12956 if (pin) /* connect to front */
12957 /* use dac 0 */
12958 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
12959}
12960
12961#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
12962#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
12963
12964static void alc662_auto_init_analog_input(struct hda_codec *codec)
12965{
12966 struct alc_spec *spec = codec->spec;
12967 int i;
12968
12969 for (i = 0; i < AUTO_PIN_LAST; i++) {
12970 hda_nid_t nid = spec->autocfg.input_pins[i];
12971 if (alc662_is_input_pin(nid)) {
12972 snd_hda_codec_write(codec, nid, 0,
12973 AC_VERB_SET_PIN_WIDGET_CONTROL,
12974 (i <= AUTO_PIN_FRONT_MIC ?
12975 PIN_VREF80 : PIN_IN));
12976 if (nid != ALC662_PIN_CD_NID)
12977 snd_hda_codec_write(codec, nid, 0,
12978 AC_VERB_SET_AMP_GAIN_MUTE,
12979 AMP_OUT_MUTE);
12980 }
12981 }
12982}
12983
12984static int alc662_parse_auto_config(struct hda_codec *codec)
12985{
12986 struct alc_spec *spec = codec->spec;
12987 int err;
12988 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
12989
12990 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12991 alc662_ignore);
12992 if (err < 0)
12993 return err;
12994 if (!spec->autocfg.line_outs)
12995 return 0; /* can't find valid BIOS pin config */
12996
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012997 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12998 if (err < 0)
12999 return err;
13000 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
13001 if (err < 0)
13002 return err;
13003 err = alc662_auto_create_extra_out(spec,
13004 spec->autocfg.speaker_pins[0],
13005 "Speaker");
13006 if (err < 0)
13007 return err;
13008 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
13009 "Headphone");
13010 if (err < 0)
13011 return err;
13012 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
13013 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013014 return err;
13015
13016 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13017
13018 if (spec->autocfg.dig_out_pin)
13019 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
13020
13021 if (spec->kctl_alloc)
13022 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13023
13024 spec->num_mux_defs = 1;
13025 spec->input_mux = &spec->private_imux;
13026
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013027 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013028 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
13029 spec->num_mixers++;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013030 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013031}
13032
13033/* additional initialization for auto-configuration model */
13034static void alc662_auto_init(struct hda_codec *codec)
13035{
13036 alc662_auto_init_multi_out(codec);
13037 alc662_auto_init_hp_out(codec);
13038 alc662_auto_init_analog_input(codec);
13039}
13040
13041static int patch_alc662(struct hda_codec *codec)
13042{
13043 struct alc_spec *spec;
13044 int err, board_config;
13045
13046 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13047 if (!spec)
13048 return -ENOMEM;
13049
13050 codec->spec = spec;
13051
13052 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
13053 alc662_models,
13054 alc662_cfg_tbl);
13055 if (board_config < 0) {
13056 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
13057 "trying auto-probe from BIOS...\n");
13058 board_config = ALC662_AUTO;
13059 }
13060
13061 if (board_config == ALC662_AUTO) {
13062 /* automatic parse from the BIOS config */
13063 err = alc662_parse_auto_config(codec);
13064 if (err < 0) {
13065 alc_free(codec);
13066 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013067 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013068 printk(KERN_INFO
13069 "hda_codec: Cannot set up configuration "
13070 "from BIOS. Using base mode...\n");
13071 board_config = ALC662_3ST_2ch_DIG;
13072 }
13073 }
13074
13075 if (board_config != ALC662_AUTO)
13076 setup_preset(spec, &alc662_presets[board_config]);
13077
13078 spec->stream_name_analog = "ALC662 Analog";
13079 spec->stream_analog_playback = &alc662_pcm_analog_playback;
13080 spec->stream_analog_capture = &alc662_pcm_analog_capture;
13081
13082 spec->stream_name_digital = "ALC662 Digital";
13083 spec->stream_digital_playback = &alc662_pcm_digital_playback;
13084 spec->stream_digital_capture = &alc662_pcm_digital_capture;
13085
13086 if (!spec->adc_nids && spec->input_mux) {
13087 spec->adc_nids = alc662_adc_nids;
13088 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
13089 }
13090
13091 codec->patch_ops = alc_patch_ops;
13092 if (board_config == ALC662_AUTO)
13093 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013094#ifdef CONFIG_SND_HDA_POWER_SAVE
13095 if (!spec->loopback.amplist)
13096 spec->loopback.amplist = alc662_loopbacks;
13097#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013098
13099 return 0;
13100}
13101
13102/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070013103 * patch entries
13104 */
13105struct hda_codec_preset snd_hda_preset_realtek[] = {
13106 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013107 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013108 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020013109 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013110 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013111 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013112 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013113 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
13114 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
13115 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013116 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
13117 .patch = patch_alc883 },
13118 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
13119 .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013120 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013121 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013122 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013123 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013124 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013125 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013126 {} /* terminator */
13127};