blob: 181db2177a1da74b8c843f855c404933b3c6aed9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010033#include "hda_patch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020063#ifdef CONFIG_SND_DEBUG
64 ALC880_TEST,
65#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010066 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020067 ALC880_MODEL_LAST /* last tag */
68};
69
70/* ALC260 models */
71enum {
72 ALC260_BASIC,
73 ALC260_HP,
Kailang Yangdf694da2005-12-05 19:42:22 +010074 ALC260_HP_3013,
75 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010076 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020077 ALC260_WILL,
78 ALC260_REPLACER_672V,
Jonathan 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,
Kailang Yang8c427222008-01-10 13:03:59 +010096 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020097 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +020098 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +020099 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200100 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100101 ALC262_LENOVO_3000,
Kailang Yangdf694da2005-12-05 19:42:22 +0100102 ALC262_AUTO,
103 ALC262_MODEL_LAST /* last tag */
104};
105
Kailang Yanga361d842007-06-05 12:30:55 +0200106/* ALC268 models */
107enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200108 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200109 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200110 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200111 ALC268_ACER,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100112 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100113 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100114#ifdef CONFIG_SND_DEBUG
115 ALC268_TEST,
116#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_AUTO,
118 ALC268_MODEL_LAST /* last tag */
119};
120
Kailang Yangf6a92242007-12-13 16:52:54 +0100121/* ALC269 models */
122enum {
123 ALC269_BASIC,
124 ALC269_AUTO,
125 ALC269_MODEL_LAST /* last tag */
126};
127
Kailang Yangdf694da2005-12-05 19:42:22 +0100128/* ALC861 models */
129enum {
130 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200131 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100132 ALC861_3ST_DIG,
133 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200134 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200135 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200136 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100137 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100138 ALC861_AUTO,
139 ALC861_MODEL_LAST,
140};
141
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100142/* ALC861-VD models */
143enum {
144 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200145 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100146 ALC861VD_3ST,
147 ALC861VD_3ST_DIG,
148 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200149 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200150 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200151 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100152 ALC861VD_AUTO,
153 ALC861VD_MODEL_LAST,
154};
155
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200156/* ALC662 models */
157enum {
158 ALC662_3ST_2ch_DIG,
159 ALC662_3ST_6ch_DIG,
160 ALC662_3ST_6ch,
161 ALC662_5ST_DIG,
162 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200163 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100164 ALC662_ASUS_EEEPC_EP20,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200165 ALC662_AUTO,
166 ALC662_MODEL_LAST,
167};
168
Kailang Yangdf694da2005-12-05 19:42:22 +0100169/* ALC882 models */
170enum {
171 ALC882_3ST_DIG,
172 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200173 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200174 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200175 ALC882_TARGA,
176 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200177 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100178 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200179 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200180 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200181 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100182 ALC882_MODEL_LAST,
183};
184
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200185/* ALC883 models */
186enum {
187 ALC883_3ST_2ch_DIG,
188 ALC883_3ST_6ch_DIG,
189 ALC883_3ST_6ch,
190 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200191 ALC883_TARGA_DIG,
192 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200193 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200194 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200195 ALC883_MEDION,
Kailang Yang272a5272007-05-14 11:00:38 +0200196 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100197 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200198 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200199 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200200 ALC888_LENOVO_MS7195_DIG,
201 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200202 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100203 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100204 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100205 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100206 ALC883_FUJITSU_PI2515,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200207 ALC883_AUTO,
208 ALC883_MODEL_LAST,
209};
210
Kailang Yangdf694da2005-12-05 19:42:22 +0100211/* for GPIO Poll */
212#define GPIO_MASK 0x03
213
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214struct alc_spec {
215 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100216 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 unsigned int num_mixers;
218
Kailang Yangdf694da2005-12-05 19:42:22 +0100219 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 * don't forget NULL
221 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200222 */
223 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Takashi Iwai16ded522005-06-10 19:58:24 +0200225 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 struct hda_pcm_stream *stream_analog_playback;
227 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100228 struct hda_pcm_stream *stream_analog_alt_playback;
229 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200231 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 struct hda_pcm_stream *stream_digital_playback;
233 struct hda_pcm_stream *stream_digital_capture;
234
235 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200236 struct hda_multi_out multiout; /* playback set-up
237 * max_channels, dacs must be set
238 * dig_out_nid and hp_nid are optional
239 */
Takashi Iwai63300792008-01-24 15:31:36 +0100240 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 /* capture */
243 unsigned int num_adc_nids;
244 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100245 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200246 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200249 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 const struct hda_input_mux *input_mux;
251 unsigned int cur_mux[3];
252
253 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100254 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200256 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100259 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200260
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200261 /* dynamic controls, init_verbs and input_mux */
262 struct auto_pin_cfg autocfg;
263 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100264 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200265 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200266 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100267
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100268 /* hooks */
269 void (*init_hook)(struct hda_codec *codec);
270 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
271
Takashi Iwai834be882006-03-01 14:16:17 +0100272 /* for pin sensing */
273 unsigned int sense_updated: 1;
274 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100275 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200276
Takashi Iwai2134ea42008-01-10 16:53:55 +0100277 /* for virtual master */
278 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200279#ifdef CONFIG_SND_HDA_POWER_SAVE
280 struct hda_loopback_check loopback;
281#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100282};
283
284/*
285 * configuration template - to be copied to the spec instance
286 */
287struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200288 struct snd_kcontrol_new *mixers[5]; /* should be identical size
289 * with spec
290 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100291 const struct hda_verb *init_verbs[5];
292 unsigned int num_dacs;
293 hda_nid_t *dac_nids;
294 hda_nid_t dig_out_nid; /* optional */
295 hda_nid_t hp_nid; /* optional */
296 unsigned int num_adc_nids;
297 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100298 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100299 hda_nid_t dig_in_nid;
300 unsigned int num_channel_mode;
301 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200302 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200303 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100304 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100305 void (*unsol_event)(struct hda_codec *, unsigned int);
306 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200307#ifdef CONFIG_SND_HDA_POWER_SAVE
308 struct hda_amp_list *loopbacks;
309#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310};
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313/*
314 * input MUX handling
315 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200316static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
317 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
320 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200321 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
322 if (mux_idx >= spec->num_mux_defs)
323 mux_idx = 0;
324 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325}
326
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200327static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
328 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
331 struct alc_spec *spec = codec->spec;
332 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
333
334 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
335 return 0;
336}
337
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200338static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
339 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
341 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
342 struct alc_spec *spec = codec->spec;
343 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200344 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100345 hda_nid_t nid = spec->capsrc_nids ?
346 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200347 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100348 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/*
353 * channel mode setting
354 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200355static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
356 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
358 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
359 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100360 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
361 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200364static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
365 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
367 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
368 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100369 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200370 spec->num_channel_mode,
371 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372}
373
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200374static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
375 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
378 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200379 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
380 spec->num_channel_mode,
381 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200382 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200383 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
384 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100388 * Control the mode of pin widget settings via the mixer. "pc" is used
389 * instead of "%" to avoid consequences of accidently treating the % as
390 * being part of a format specifier. Maximum allowed length of a value is
391 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100392 *
393 * Note: some retasking pin complexes seem to ignore requests for input
394 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
395 * are requested. Therefore order this list so that this behaviour will not
396 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200397 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
398 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200399 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100400static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100401 "Mic 50pc bias", "Mic 80pc bias",
402 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100403};
404static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100405 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100406};
407/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200408 * in the pin being assumed to be exclusively an input or an output pin. In
409 * addition, "input" pins may or may not process the mic bias option
410 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
411 * accept requests for bias as of chip versions up to March 2006) and/or
412 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100413 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200414#define ALC_PIN_DIR_IN 0x00
415#define ALC_PIN_DIR_OUT 0x01
416#define ALC_PIN_DIR_INOUT 0x02
417#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
418#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100419
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200420/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100421 * For each direction the minimum and maximum values are given.
422 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200423static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100424 { 0, 2 }, /* ALC_PIN_DIR_IN */
425 { 3, 4 }, /* ALC_PIN_DIR_OUT */
426 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200427 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
428 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100429};
430#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
431#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
432#define alc_pin_mode_n_items(_dir) \
433 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
434
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200435static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
436 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200437{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100438 unsigned int item_num = uinfo->value.enumerated.item;
439 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
440
441 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200442 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100443 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
444
445 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
446 item_num = alc_pin_mode_min(dir);
447 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200448 return 0;
449}
450
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200451static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200453{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100454 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200455 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
456 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100457 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200458 long *valp = 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 Woithea9430dd2005-09-16 19:12:48 +0200462
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100463 /* Find enumerated value for current pinctl setting */
464 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200465 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100466 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200467 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100468 return 0;
469}
470
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200471static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
472 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100473{
474 signed int change;
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 hda_nid_t nid = kcontrol->private_value & 0xffff;
477 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
478 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200479 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
480 AC_VERB_GET_PIN_WIDGET_CONTROL,
481 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100482
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200483 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100484 val = alc_pin_mode_min(dir);
485
486 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100487 if (change) {
488 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200489 snd_hda_codec_write_cache(codec, nid, 0,
490 AC_VERB_SET_PIN_WIDGET_CONTROL,
491 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100492
493 /* Also enable the retasking pin's input/output as required
494 * for the requested pin mode. Enum values of 2 or less are
495 * input modes.
496 *
497 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200498 * reduces noise slightly (particularly on input) so we'll
499 * do it. However, having both input and output buffers
500 * enabled simultaneously doesn't seem to be problematic if
501 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100502 */
503 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200504 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
505 HDA_AMP_MUTE, HDA_AMP_MUTE);
506 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
507 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100508 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200509 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
510 HDA_AMP_MUTE, HDA_AMP_MUTE);
511 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
512 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100513 }
514 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200515 return change;
516}
517
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100518#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200519 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100520 .info = alc_pin_mode_info, \
521 .get = alc_pin_mode_get, \
522 .put = alc_pin_mode_put, \
523 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100524
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100525/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
526 * together using a mask with more than one bit set. This control is
527 * currently used only by the ALC260 test model. At this stage they are not
528 * needed for any "production" models.
529 */
530#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200531#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200532
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200533static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
534 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100535{
536 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
537 hda_nid_t nid = kcontrol->private_value & 0xffff;
538 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
539 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200540 unsigned int val = snd_hda_codec_read(codec, nid, 0,
541 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100542
543 *valp = (val & mask) != 0;
544 return 0;
545}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200546static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
547 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100548{
549 signed int change;
550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
551 hda_nid_t nid = kcontrol->private_value & 0xffff;
552 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
553 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200554 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
555 AC_VERB_GET_GPIO_DATA,
556 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100557
558 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200559 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
560 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100561 gpio_data &= ~mask;
562 else
563 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200564 snd_hda_codec_write_cache(codec, nid, 0,
565 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100566
567 return change;
568}
569#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
570 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
571 .info = alc_gpio_data_info, \
572 .get = alc_gpio_data_get, \
573 .put = alc_gpio_data_put, \
574 .private_value = nid | (mask<<16) }
575#endif /* CONFIG_SND_DEBUG */
576
Jonathan Woithe92621f12006-02-28 11:47:47 +0100577/* A switch control to allow the enabling of the digital IO pins on the
578 * ALC260. This is incredibly simplistic; the intention of this control is
579 * to provide something in the test model allowing digital outputs to be
580 * identified if present. If models are found which can utilise these
581 * outputs a more complete mixer control can be devised for those models if
582 * necessary.
583 */
584#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200585#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200586
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200587static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
588 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100589{
590 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
591 hda_nid_t nid = kcontrol->private_value & 0xffff;
592 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
593 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200594 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100595 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100596
597 *valp = (val & mask) != 0;
598 return 0;
599}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200600static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
601 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100602{
603 signed int change;
604 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
605 hda_nid_t nid = kcontrol->private_value & 0xffff;
606 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
607 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200608 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100609 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200610 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100611
612 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200613 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100614 if (val==0)
615 ctrl_data &= ~mask;
616 else
617 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200618 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
619 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100620
621 return change;
622}
623#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
624 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
625 .info = alc_spdif_ctrl_info, \
626 .get = alc_spdif_ctrl_get, \
627 .put = alc_spdif_ctrl_put, \
628 .private_value = nid | (mask<<16) }
629#endif /* CONFIG_SND_DEBUG */
630
Jonathan Woithef8225f62008-01-08 12:16:54 +0100631/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
632 * Again, this is only used in the ALC26x test models to help identify when
633 * the EAPD line must be asserted for features to work.
634 */
635#ifdef CONFIG_SND_DEBUG
636#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
637
638static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
639 struct snd_ctl_elem_value *ucontrol)
640{
641 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
642 hda_nid_t nid = kcontrol->private_value & 0xffff;
643 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
644 long *valp = ucontrol->value.integer.value;
645 unsigned int val = snd_hda_codec_read(codec, nid, 0,
646 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
647
648 *valp = (val & mask) != 0;
649 return 0;
650}
651
652static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
653 struct snd_ctl_elem_value *ucontrol)
654{
655 int change;
656 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
657 hda_nid_t nid = kcontrol->private_value & 0xffff;
658 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
659 long val = *ucontrol->value.integer.value;
660 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
661 AC_VERB_GET_EAPD_BTLENABLE,
662 0x00);
663
664 /* Set/unset the masked control bit(s) as needed */
665 change = (!val ? 0 : mask) != (ctrl_data & mask);
666 if (!val)
667 ctrl_data &= ~mask;
668 else
669 ctrl_data |= mask;
670 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
671 ctrl_data);
672
673 return change;
674}
675
676#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
677 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
678 .info = alc_eapd_ctrl_info, \
679 .get = alc_eapd_ctrl_get, \
680 .put = alc_eapd_ctrl_put, \
681 .private_value = nid | (mask<<16) }
682#endif /* CONFIG_SND_DEBUG */
683
Kailang Yangdf694da2005-12-05 19:42:22 +0100684/*
685 * set up from the preset table
686 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200687static void setup_preset(struct alc_spec *spec,
688 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100689{
690 int i;
691
692 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
693 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200694 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
695 i++)
696 spec->init_verbs[spec->num_init_verbs++] =
697 preset->init_verbs[i];
Kailang Yangdf694da2005-12-05 19:42:22 +0100698
699 spec->channel_mode = preset->channel_mode;
700 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200701 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100702
703 spec->multiout.max_channels = spec->channel_mode[0].channels;
704
705 spec->multiout.num_dacs = preset->num_dacs;
706 spec->multiout.dac_nids = preset->dac_nids;
707 spec->multiout.dig_out_nid = preset->dig_out_nid;
708 spec->multiout.hp_nid = preset->hp_nid;
709
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200710 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200711 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200712 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100713 spec->input_mux = preset->input_mux;
714
715 spec->num_adc_nids = preset->num_adc_nids;
716 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100717 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100718 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100719
720 spec->unsol_event = preset->unsol_event;
721 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200722#ifdef CONFIG_SND_HDA_POWER_SAVE
723 spec->loopback.amplist = preset->loopbacks;
724#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100725}
726
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200727/* Enable GPIO mask and set output */
728static struct hda_verb alc_gpio1_init_verbs[] = {
729 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
730 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
731 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
732 { }
733};
734
735static struct hda_verb alc_gpio2_init_verbs[] = {
736 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
737 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
738 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
739 { }
740};
741
Kailang Yangbdd148a2007-05-08 15:19:08 +0200742static struct hda_verb alc_gpio3_init_verbs[] = {
743 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
744 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
745 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
746 { }
747};
748
Kailang Yangc9b58002007-10-16 14:30:01 +0200749static void alc_sku_automute(struct hda_codec *codec)
750{
751 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200752 unsigned int present;
753 unsigned int hp_nid = spec->autocfg.hp_pins[0];
754 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
755
756 /* need to execute and sync at first */
757 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
758 present = snd_hda_codec_read(codec, hp_nid, 0,
759 AC_VERB_GET_PIN_SENSE, 0);
760 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100761 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
762 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200763}
764
765/* unsolicited event for HP jack sensing */
766static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
767{
768 if (codec->vendor_id == 0x10ec0880)
769 res >>= 28;
770 else
771 res >>= 26;
772 if (res != ALC880_HP_EVENT)
773 return;
774
775 alc_sku_automute(codec);
776}
777
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200778/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
779 * 31 ~ 16 : Manufacture ID
780 * 15 ~ 8 : SKU ID
781 * 7 ~ 0 : Assembly ID
782 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
783 */
784static void alc_subsystem_id(struct hda_codec *codec,
785 unsigned int porta, unsigned int porte,
786 unsigned int portd)
787{
Kailang Yangc9b58002007-10-16 14:30:01 +0200788 unsigned int ass, tmp, i;
789 unsigned nid;
790 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200791
Kailang Yangc9b58002007-10-16 14:30:01 +0200792 ass = codec->subsystem_id & 0xffff;
793 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
794 goto do_sku;
795
796 /*
797 * 31~30 : port conetcivity
798 * 29~21 : reserve
799 * 20 : PCBEEP input
800 * 19~16 : Check sum (15:1)
801 * 15~1 : Custom
802 * 0 : override
803 */
804 nid = 0x1d;
805 if (codec->vendor_id == 0x10ec0260)
806 nid = 0x17;
807 ass = snd_hda_codec_read(codec, nid, 0,
808 AC_VERB_GET_CONFIG_DEFAULT, 0);
809 if (!(ass & 1) && !(ass & 0x100000))
810 return;
811 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200812 return;
813
Kailang Yangc9b58002007-10-16 14:30:01 +0200814 /* check sum */
815 tmp = 0;
816 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100817 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200818 tmp++;
819 }
820 if (((ass >> 16) & 0xf) != tmp)
821 return;
822do_sku:
823 /*
824 * 0 : override
825 * 1 : Swap Jack
826 * 2 : 0 --> Desktop, 1 --> Laptop
827 * 3~5 : External Amplifier control
828 * 7~6 : Reserved
829 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200830 tmp = (ass & 0x38) >> 3; /* external Amp control */
831 switch (tmp) {
832 case 1:
833 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
834 break;
835 case 3:
836 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
837 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200838 case 7:
839 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
840 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200841 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200842 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200843 case 0x10ec0260:
844 snd_hda_codec_write(codec, 0x0f, 0,
845 AC_VERB_SET_EAPD_BTLENABLE, 2);
846 snd_hda_codec_write(codec, 0x10, 0,
847 AC_VERB_SET_EAPD_BTLENABLE, 2);
848 break;
849 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200850 case 0x10ec0267:
851 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200852 case 0x10ec0269:
853 case 0x10ec0862:
854 case 0x10ec0662:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200855 snd_hda_codec_write(codec, 0x14, 0,
856 AC_VERB_SET_EAPD_BTLENABLE, 2);
857 snd_hda_codec_write(codec, 0x15, 0,
858 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200859 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200860 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200861 switch (codec->vendor_id) {
862 case 0x10ec0260:
863 snd_hda_codec_write(codec, 0x1a, 0,
864 AC_VERB_SET_COEF_INDEX, 7);
865 tmp = snd_hda_codec_read(codec, 0x1a, 0,
866 AC_VERB_GET_PROC_COEF, 0);
867 snd_hda_codec_write(codec, 0x1a, 0,
868 AC_VERB_SET_COEF_INDEX, 7);
869 snd_hda_codec_write(codec, 0x1a, 0,
870 AC_VERB_SET_PROC_COEF,
871 tmp | 0x2010);
872 break;
873 case 0x10ec0262:
874 case 0x10ec0880:
875 case 0x10ec0882:
876 case 0x10ec0883:
877 case 0x10ec0885:
878 case 0x10ec0888:
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 | 0x2010);
888 break;
889 case 0x10ec0267:
890 case 0x10ec0268:
891 snd_hda_codec_write(codec, 0x20, 0,
892 AC_VERB_SET_COEF_INDEX, 7);
893 tmp = snd_hda_codec_read(codec, 0x20, 0,
894 AC_VERB_GET_PROC_COEF, 0);
895 snd_hda_codec_write(codec, 0x20, 0,
896 AC_VERB_SET_COEF_INDEX, 7);
897 snd_hda_codec_write(codec, 0x20, 0,
898 AC_VERB_SET_PROC_COEF,
899 tmp | 0x3000);
900 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200901 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200902 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200903 break;
904 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200905
Kailang Yang8c427222008-01-10 13:03:59 +0100906 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200907 * when the external headphone out jack is plugged"
908 */
Kailang Yang8c427222008-01-10 13:03:59 +0100909 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200910 return;
911 /*
912 * 10~8 : Jack location
913 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
914 * 14~13: Resvered
915 * 15 : 1 --> enable the function "Mute internal speaker
916 * when the external headphone out jack is plugged"
917 */
918 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +0100919 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +0200920 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +0100921 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +0200922 else
923 return;
924 }
925
926 if (!spec->autocfg.hp_pins[0]) {
927 tmp = (ass >> 11) & 0x3; /* HP to chassis */
928 if (tmp == 0)
929 spec->autocfg.hp_pins[0] = porta;
930 else if (tmp == 1)
931 spec->autocfg.hp_pins[0] = porte;
932 else if (tmp == 2)
933 spec->autocfg.hp_pins[0] = portd;
934 else
935 return;
936 }
937
938 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
939 AC_VERB_SET_UNSOLICITED_ENABLE,
940 AC_USRSP_EN | ALC880_HP_EVENT);
941 spec->unsol_event = alc_sku_unsol_event;
942 spec->init_hook = alc_sku_automute;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200943}
944
Takashi Iwai41e41f12005-06-08 14:48:49 +0200945/*
Takashi Iwaif95474e2007-07-10 00:47:43 +0200946 * Fix-up pin default configurations
947 */
948
949struct alc_pincfg {
950 hda_nid_t nid;
951 u32 val;
952};
953
954static void alc_fix_pincfg(struct hda_codec *codec,
955 const struct snd_pci_quirk *quirk,
956 const struct alc_pincfg **pinfix)
957{
958 const struct alc_pincfg *cfg;
959
960 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
961 if (!quirk)
962 return;
963
964 cfg = pinfix[quirk->value];
965 for (; cfg->nid; cfg++) {
966 int i;
967 u32 val = cfg->val;
968 for (i = 0; i < 4; i++) {
969 snd_hda_codec_write(codec, cfg->nid, 0,
970 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
971 val & 0xff);
972 val >>= 8;
973 }
974 }
975}
976
977/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200978 * ALC880 3-stack model
979 *
980 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200981 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
982 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 */
984
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200985static hda_nid_t alc880_dac_nids[4] = {
986 /* front, rear, clfe, rear_surr */
987 0x02, 0x05, 0x04, 0x03
988};
989
990static hda_nid_t alc880_adc_nids[3] = {
991 /* ADC0-2 */
992 0x07, 0x08, 0x09,
993};
994
995/* The datasheet says the node 0x07 is connected from inputs,
996 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +0100997 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200999static hda_nid_t alc880_adc_nids_alt[2] = {
1000 /* ADC1-2 */
1001 0x08, 0x09,
1002};
1003
1004#define ALC880_DIGOUT_NID 0x06
1005#define ALC880_DIGIN_NID 0x0a
1006
1007static struct hda_input_mux alc880_capture_source = {
1008 .num_items = 4,
1009 .items = {
1010 { "Mic", 0x0 },
1011 { "Front Mic", 0x3 },
1012 { "Line", 0x2 },
1013 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001015};
1016
1017/* channel source setting (2/6 channel selection for 3-stack) */
1018/* 2ch mode */
1019static struct hda_verb alc880_threestack_ch2_init[] = {
1020 /* set line-in to input, mute it */
1021 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1022 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1023 /* set mic-in to input vref 80%, mute it */
1024 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1025 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 { } /* end */
1027};
1028
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001029/* 6ch mode */
1030static struct hda_verb alc880_threestack_ch6_init[] = {
1031 /* set line-in to output, unmute it */
1032 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1033 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1034 /* set mic-in to output, unmute it */
1035 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1036 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1037 { } /* end */
1038};
1039
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001040static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001041 { 2, alc880_threestack_ch2_init },
1042 { 6, alc880_threestack_ch6_init },
1043};
1044
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001045static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001046 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001047 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001048 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001049 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001050 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1051 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001052 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1053 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1055 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1056 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1057 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1058 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1059 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1060 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1061 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1062 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1063 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001065 {
1066 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1067 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001068 .info = alc_ch_mode_info,
1069 .get = alc_ch_mode_get,
1070 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001071 },
1072 { } /* end */
1073};
1074
1075/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001076static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001077 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1078 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1079 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1080 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1081 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1082 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1083 {
1084 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1085 /* The multiple "Capture Source" controls confuse alsamixer
1086 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001087 */
1088 /* .name = "Capture Source", */
1089 .name = "Input Source",
1090 .count = 3,
1091 .info = alc_mux_enum_info,
1092 .get = alc_mux_enum_get,
1093 .put = alc_mux_enum_put,
1094 },
1095 { } /* end */
1096};
1097
1098/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001099static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001100 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1101 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1102 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1103 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 {
1105 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1106 /* The multiple "Capture Source" controls confuse alsamixer
1107 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 */
1109 /* .name = "Capture Source", */
1110 .name = "Input Source",
1111 .count = 2,
1112 .info = alc_mux_enum_info,
1113 .get = alc_mux_enum_get,
1114 .put = alc_mux_enum_put,
1115 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 { } /* end */
1117};
1118
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001119
1120
1121/*
1122 * ALC880 5-stack model
1123 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001124 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1125 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001126 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1127 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1128 */
1129
1130/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001131static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001132 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001133 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 { } /* end */
1135};
1136
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001137/* channel source setting (6/8 channel selection for 5-stack) */
1138/* 6ch mode */
1139static struct hda_verb alc880_fivestack_ch6_init[] = {
1140 /* set line-in to input, mute it */
1141 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1142 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001143 { } /* end */
1144};
1145
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001146/* 8ch mode */
1147static struct hda_verb alc880_fivestack_ch8_init[] = {
1148 /* set line-in to output, unmute it */
1149 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1150 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1151 { } /* end */
1152};
1153
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001154static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001155 { 6, alc880_fivestack_ch6_init },
1156 { 8, alc880_fivestack_ch8_init },
1157};
1158
1159
1160/*
1161 * ALC880 6-stack model
1162 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001163 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1164 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001165 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1166 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1167 */
1168
1169static hda_nid_t alc880_6st_dac_nids[4] = {
1170 /* front, rear, clfe, rear_surr */
1171 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001172};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001173
1174static struct hda_input_mux alc880_6stack_capture_source = {
1175 .num_items = 4,
1176 .items = {
1177 { "Mic", 0x0 },
1178 { "Front Mic", 0x1 },
1179 { "Line", 0x2 },
1180 { "CD", 0x4 },
1181 },
1182};
1183
1184/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001185static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001186 { 8, NULL },
1187};
1188
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001189static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001190 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001191 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001192 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001193 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001194 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1195 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001196 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1197 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001198 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001199 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001200 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1201 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1202 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1203 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1204 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1205 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1206 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1207 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1208 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1209 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001210 {
1211 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1212 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001213 .info = alc_ch_mode_info,
1214 .get = alc_ch_mode_get,
1215 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001216 },
1217 { } /* end */
1218};
1219
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001220
1221/*
1222 * ALC880 W810 model
1223 *
1224 * W810 has rear IO for:
1225 * Front (DAC 02)
1226 * Surround (DAC 03)
1227 * Center/LFE (DAC 04)
1228 * Digital out (06)
1229 *
1230 * The system also has a pair of internal speakers, and a headphone jack.
1231 * These are both connected to Line2 on the codec, hence to DAC 02.
1232 *
1233 * There is a variable resistor to control the speaker or headphone
1234 * volume. This is a hardware-only device without a software API.
1235 *
1236 * Plugging headphones in will disable the internal speakers. This is
1237 * implemented in hardware, not via the driver using jack sense. In
1238 * a similar fashion, plugging into the rear socket marked "front" will
1239 * disable both the speakers and headphones.
1240 *
1241 * For input, there's a microphone jack, and an "audio in" jack.
1242 * These may not do anything useful with this driver yet, because I
1243 * haven't setup any initialization verbs for these yet...
1244 */
1245
1246static hda_nid_t alc880_w810_dac_nids[3] = {
1247 /* front, rear/surround, clfe */
1248 0x02, 0x03, 0x04
1249};
1250
1251/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001252static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001253 { 6, NULL }
1254};
1255
1256/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001257static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001258 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001259 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001260 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001261 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001262 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1263 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001264 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1265 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001266 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1267 { } /* end */
1268};
1269
1270
1271/*
1272 * Z710V model
1273 *
1274 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001275 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1276 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001277 */
1278
1279static hda_nid_t alc880_z71v_dac_nids[1] = {
1280 0x02
1281};
1282#define ALC880_Z71V_HP_DAC 0x03
1283
1284/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001285static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001286 { 2, NULL }
1287};
1288
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001289static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001290 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001291 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001292 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001293 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001294 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1295 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1296 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1297 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1298 { } /* end */
1299};
1300
1301
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001302/*
1303 * ALC880 F1734 model
1304 *
1305 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1306 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1307 */
1308
1309static hda_nid_t alc880_f1734_dac_nids[1] = {
1310 0x03
1311};
1312#define ALC880_F1734_HP_DAC 0x02
1313
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001314static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001315 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001316 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001317 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1318 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001319 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1320 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001321 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1322 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001323 { } /* end */
1324};
1325
Takashi Iwai937b4162008-02-11 14:52:36 +01001326static struct hda_input_mux alc880_f1734_capture_source = {
1327 .num_items = 2,
1328 .items = {
1329 { "Mic", 0x1 },
1330 { "CD", 0x4 },
1331 },
1332};
1333
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001334
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001335/*
1336 * ALC880 ASUS model
1337 *
1338 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1339 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1340 * Mic = 0x18, Line = 0x1a
1341 */
1342
1343#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1344#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1345
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001346static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001347 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001348 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001349 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001350 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001351 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1352 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001353 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1354 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001355 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1356 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1357 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1358 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1359 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1360 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001361 {
1362 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1363 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001364 .info = alc_ch_mode_info,
1365 .get = alc_ch_mode_get,
1366 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001367 },
1368 { } /* end */
1369};
1370
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001371/*
1372 * ALC880 ASUS W1V model
1373 *
1374 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1375 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1376 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1377 */
1378
1379/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001380static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001381 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1382 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001383 { } /* end */
1384};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001385
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001386/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001387static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001388 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1389 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1390 { } /* end */
1391};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001392
Kailang Yangdf694da2005-12-05 19:42:22 +01001393/* TCL S700 */
1394static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1395 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1396 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1397 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1398 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1399 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1400 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1401 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1402 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1403 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1404 {
1405 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1406 /* The multiple "Capture Source" controls confuse alsamixer
1407 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001408 */
1409 /* .name = "Capture Source", */
1410 .name = "Input Source",
1411 .count = 1,
1412 .info = alc_mux_enum_info,
1413 .get = alc_mux_enum_get,
1414 .put = alc_mux_enum_put,
1415 },
1416 { } /* end */
1417};
1418
Kailang Yangccc656c2006-10-17 12:32:26 +02001419/* Uniwill */
1420static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001421 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1422 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1423 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1424 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001425 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1426 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1427 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1428 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1429 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1430 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1431 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1432 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1433 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1434 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1435 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1436 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1437 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1438 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1439 {
1440 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1441 .name = "Channel Mode",
1442 .info = alc_ch_mode_info,
1443 .get = alc_ch_mode_get,
1444 .put = alc_ch_mode_put,
1445 },
1446 { } /* end */
1447};
1448
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001449static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1450 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1451 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1452 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1453 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1454 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1455 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1456 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1457 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1458 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1459 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1460 { } /* end */
1461};
1462
Kailang Yangccc656c2006-10-17 12:32:26 +02001463static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001464 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1465 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1466 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1467 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001468 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1469 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1470 { } /* end */
1471};
1472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001474 * virtual master controls
1475 */
1476
1477/*
1478 * slave controls for virtual master
1479 */
1480static const char *alc_slave_vols[] = {
1481 "Front Playback Volume",
1482 "Surround Playback Volume",
1483 "Center Playback Volume",
1484 "LFE Playback Volume",
1485 "Side Playback Volume",
1486 "Headphone Playback Volume",
1487 "Speaker Playback Volume",
1488 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001489 "Line-Out Playback Volume",
1490 NULL,
1491};
1492
1493static const char *alc_slave_sws[] = {
1494 "Front Playback Switch",
1495 "Surround Playback Switch",
1496 "Center Playback Switch",
1497 "LFE Playback Switch",
1498 "Side Playback Switch",
1499 "Headphone Playback Switch",
1500 "Speaker Playback Switch",
1501 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001502 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001503 NULL,
1504};
1505
1506/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001507 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 */
1509static int alc_build_controls(struct hda_codec *codec)
1510{
1511 struct alc_spec *spec = codec->spec;
1512 int err;
1513 int i;
1514
1515 for (i = 0; i < spec->num_mixers; i++) {
1516 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1517 if (err < 0)
1518 return err;
1519 }
1520
1521 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001522 err = snd_hda_create_spdif_out_ctls(codec,
1523 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (err < 0)
1525 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001526 err = snd_hda_create_spdif_share_sw(codec,
1527 &spec->multiout);
1528 if (err < 0)
1529 return err;
1530 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 }
1532 if (spec->dig_in_nid) {
1533 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1534 if (err < 0)
1535 return err;
1536 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001537
1538 /* if we have no master control, let's create it */
1539 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001540 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001541 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001542 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001543 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001544 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001545 if (err < 0)
1546 return err;
1547 }
1548 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1549 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1550 NULL, alc_slave_sws);
1551 if (err < 0)
1552 return err;
1553 }
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return 0;
1556}
1557
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001558
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559/*
1560 * initialize the codec volumes, etc
1561 */
1562
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001563/*
1564 * generic initialization of ADC, input mixers and output mixers
1565 */
1566static struct hda_verb alc880_volume_init_verbs[] = {
1567 /*
1568 * Unmute ADC0-2 and set the default input to mic-in
1569 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001570 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001571 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001572 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001573 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001574 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001575 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001577 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1578 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001579 * Note: PASD motherboards uses the Line In 2 as the input for front
1580 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001582 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001583 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1584 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1585 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1586 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1587 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1588 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1589 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001591 /*
1592 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001594 /* set vol=0 to output mixers */
1595 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1596 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1597 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1598 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1599 /* set up input amps for analog loopback */
1600 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001601 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1602 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001603 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1604 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001605 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1606 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001607 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1608 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
1610 { }
1611};
1612
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001613/*
1614 * 3-stack pin configuration:
1615 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1616 */
1617static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1618 /*
1619 * preset connection lists of input pins
1620 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1621 */
1622 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1623 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1624 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1625
1626 /*
1627 * Set pin mode and muting
1628 */
1629 /* set front pin widgets 0x14 for output */
1630 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1631 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1632 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1633 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1634 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1635 /* Mic2 (as headphone out) for HP output */
1636 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1637 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1638 /* Line In pin widget for input */
1639 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1640 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1641 /* Line2 (as front mic) pin widget for input and vref at 80% */
1642 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1643 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1644 /* CD pin widget for input */
1645 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1646
1647 { }
1648};
1649
1650/*
1651 * 5-stack pin configuration:
1652 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1653 * line-in/side = 0x1a, f-mic = 0x1b
1654 */
1655static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1656 /*
1657 * preset connection lists of input pins
1658 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1659 */
1660 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1661 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1662
1663 /*
1664 * Set pin mode and muting
1665 */
1666 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001667 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1668 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1669 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1670 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001671 /* unmute pins for output (no gain on this amp) */
1672 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1673 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1674 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1675 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001678 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001679 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1680 /* Mic2 (as headphone out) for HP output */
1681 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001682 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001683 /* Line In pin widget for input */
1684 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1685 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1686 /* Line2 (as front mic) pin widget for input and vref at 80% */
1687 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1688 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1689 /* CD pin widget for input */
1690 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 { }
1693};
1694
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001695/*
1696 * W810 pin configuration:
1697 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1698 */
1699static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* hphone/speaker input selector: front DAC */
1701 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1702
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001703 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1704 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1705 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1706 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1707 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1708 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1709
1710 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001711 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 { }
1714};
1715
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001716/*
1717 * Z71V pin configuration:
1718 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1719 */
1720static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001721 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001722 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001723 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001724 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001725
Takashi Iwai16ded522005-06-10 19:58:24 +02001726 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001727 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001728 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001729 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001730
1731 { }
1732};
1733
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001734/*
1735 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001736 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1737 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001738 */
1739static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1740 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1741
Takashi Iwai16ded522005-06-10 19:58:24 +02001742 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001743 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001744 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001745 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001746 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001747 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001748 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001749 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1750
Takashi Iwai16ded522005-06-10 19:58:24 +02001751 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001753 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001754 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001755 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001756 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001757 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001758 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001759 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1760
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001761 { }
1762};
Takashi Iwai16ded522005-06-10 19:58:24 +02001763
Kailang Yangccc656c2006-10-17 12:32:26 +02001764/*
1765 * Uniwill pin configuration:
1766 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1767 * line = 0x1a
1768 */
1769static struct hda_verb alc880_uniwill_init_verbs[] = {
1770 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1771
1772 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1773 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1774 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1775 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1776 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1777 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1778 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1779 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1780 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1781 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1782 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1783 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1784 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1785 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1786
1787 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1788 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1789 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1790 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1791 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1792 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1793 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1794 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1795 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1796
1797 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1798 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1799
1800 { }
1801};
1802
1803/*
1804* Uniwill P53
1805* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1806 */
1807static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1808 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1809
1810 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1811 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1812 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1813 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1814 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1815 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1816 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1817 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1818 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1819 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1820 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1821 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1822
1823 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1824 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1825 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1826 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1827 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1828 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1829
1830 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1831 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1832
1833 { }
1834};
1835
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001836static struct hda_verb alc880_beep_init_verbs[] = {
1837 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1838 { }
1839};
1840
Kailang Yangccc656c2006-10-17 12:32:26 +02001841/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001842static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001843{
1844 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001845 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001846
1847 present = snd_hda_codec_read(codec, 0x14, 0,
1848 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001849 bits = present ? HDA_AMP_MUTE : 0;
1850 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1851 HDA_AMP_MUTE, bits);
1852 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1853 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001854}
1855
1856/* auto-toggle front mic */
1857static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1858{
1859 unsigned int present;
1860 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001861
1862 present = snd_hda_codec_read(codec, 0x18, 0,
1863 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001864 bits = present ? HDA_AMP_MUTE : 0;
1865 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001866}
1867
1868static void alc880_uniwill_automute(struct hda_codec *codec)
1869{
1870 alc880_uniwill_hp_automute(codec);
1871 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001872}
1873
1874static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1875 unsigned int res)
1876{
1877 /* Looks like the unsol event is incompatible with the standard
1878 * definition. 4bit tag is placed at 28 bit!
1879 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001880 switch (res >> 28) {
1881 case ALC880_HP_EVENT:
1882 alc880_uniwill_hp_automute(codec);
1883 break;
1884 case ALC880_MIC_EVENT:
1885 alc880_uniwill_mic_automute(codec);
1886 break;
1887 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001888}
1889
1890static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1891{
1892 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001893 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001894
1895 present = snd_hda_codec_read(codec, 0x14, 0,
1896 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001897 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02001898 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001899}
1900
1901static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1902{
1903 unsigned int present;
1904
1905 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001906 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1907 present &= HDA_AMP_VOLMASK;
1908 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1909 HDA_AMP_VOLMASK, present);
1910 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1911 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001912}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001913
Kailang Yangccc656c2006-10-17 12:32:26 +02001914static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1915 unsigned int res)
1916{
1917 /* Looks like the unsol event is incompatible with the standard
1918 * definition. 4bit tag is placed at 28 bit!
1919 */
1920 if ((res >> 28) == ALC880_HP_EVENT)
1921 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001922 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001923 alc880_uniwill_p53_dcvol_automute(codec);
1924}
1925
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001926/*
1927 * F1734 pin configuration:
1928 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1929 */
1930static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01001931 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001932 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1933 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1934 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1935 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1936
1937 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1938 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1939 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1940 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1941
1942 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1943 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01001944 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001945 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1946 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1947 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1948 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1949 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1950 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001951
Takashi Iwai937b4162008-02-11 14:52:36 +01001952 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
1953 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
1954
Takashi Iwai16ded522005-06-10 19:58:24 +02001955 { }
1956};
1957
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001958/*
1959 * ASUS pin configuration:
1960 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1961 */
1962static struct hda_verb alc880_pin_asus_init_verbs[] = {
1963 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1964 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1965 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1966 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1967
1968 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1969 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1970 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1971 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1972 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1973 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1974 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1976
1977 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1978 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1979 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1980 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1981 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1982 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1983 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1984 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1985 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1986
1987 { }
1988};
1989
1990/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001991#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1992#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001993
Kailang Yangdf694da2005-12-05 19:42:22 +01001994/* Clevo m520g init */
1995static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1996 /* headphone output */
1997 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1998 /* line-out */
1999 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2000 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2001 /* Line-in */
2002 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2003 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2004 /* CD */
2005 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2006 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2007 /* Mic1 (rear panel) */
2008 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2009 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2010 /* Mic2 (front panel) */
2011 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2012 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2013 /* headphone */
2014 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2015 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2016 /* change to EAPD mode */
2017 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2018 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2019
2020 { }
2021};
2022
2023static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002024 /* change to EAPD mode */
2025 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2026 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2027
Kailang Yangdf694da2005-12-05 19:42:22 +01002028 /* Headphone output */
2029 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2030 /* Front output*/
2031 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2032 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2033
2034 /* Line In pin widget for input */
2035 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2036 /* CD pin widget for input */
2037 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2038 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2039 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2040
2041 /* change to EAPD mode */
2042 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2043 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2044
2045 { }
2046};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002047
2048/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002049 * LG m1 express dual
2050 *
2051 * Pin assignment:
2052 * Rear Line-In/Out (blue): 0x14
2053 * Build-in Mic-In: 0x15
2054 * Speaker-out: 0x17
2055 * HP-Out (green): 0x1b
2056 * Mic-In/Out (red): 0x19
2057 * SPDIF-Out: 0x1e
2058 */
2059
2060/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2061static hda_nid_t alc880_lg_dac_nids[3] = {
2062 0x05, 0x02, 0x03
2063};
2064
2065/* seems analog CD is not working */
2066static struct hda_input_mux alc880_lg_capture_source = {
2067 .num_items = 3,
2068 .items = {
2069 { "Mic", 0x1 },
2070 { "Line", 0x5 },
2071 { "Internal Mic", 0x6 },
2072 },
2073};
2074
2075/* 2,4,6 channel modes */
2076static struct hda_verb alc880_lg_ch2_init[] = {
2077 /* set line-in and mic-in to input */
2078 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2079 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2080 { }
2081};
2082
2083static struct hda_verb alc880_lg_ch4_init[] = {
2084 /* set line-in to out and mic-in to input */
2085 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2086 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2087 { }
2088};
2089
2090static struct hda_verb alc880_lg_ch6_init[] = {
2091 /* set line-in and mic-in to output */
2092 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2093 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2094 { }
2095};
2096
2097static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2098 { 2, alc880_lg_ch2_init },
2099 { 4, alc880_lg_ch4_init },
2100 { 6, alc880_lg_ch6_init },
2101};
2102
2103static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002104 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2105 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002106 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2107 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2108 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2109 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2110 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2111 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2112 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2113 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2114 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2115 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2116 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2117 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2118 {
2119 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2120 .name = "Channel Mode",
2121 .info = alc_ch_mode_info,
2122 .get = alc_ch_mode_get,
2123 .put = alc_ch_mode_put,
2124 },
2125 { } /* end */
2126};
2127
2128static struct hda_verb alc880_lg_init_verbs[] = {
2129 /* set capture source to mic-in */
2130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2131 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2132 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2133 /* mute all amp mixer inputs */
2134 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002135 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2136 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002137 /* line-in to input */
2138 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2139 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2140 /* built-in mic */
2141 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2142 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2143 /* speaker-out */
2144 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2145 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2146 /* mic-in to input */
2147 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2148 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2149 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2150 /* HP-out */
2151 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2152 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2153 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2154 /* jack sense */
2155 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2156 { }
2157};
2158
2159/* toggle speaker-output according to the hp-jack state */
2160static void alc880_lg_automute(struct hda_codec *codec)
2161{
2162 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002163 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002164
2165 present = snd_hda_codec_read(codec, 0x1b, 0,
2166 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002167 bits = present ? HDA_AMP_MUTE : 0;
2168 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2169 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002170}
2171
2172static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2173{
2174 /* Looks like the unsol event is incompatible with the standard
2175 * definition. 4bit tag is placed at 28 bit!
2176 */
2177 if ((res >> 28) == 0x01)
2178 alc880_lg_automute(codec);
2179}
2180
2181/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002182 * LG LW20
2183 *
2184 * Pin assignment:
2185 * Speaker-out: 0x14
2186 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002187 * Built-in Mic-In: 0x19
2188 * Line-In: 0x1b
2189 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002190 * SPDIF-Out: 0x1e
2191 */
2192
Takashi Iwaid6815182006-03-23 16:06:23 +01002193static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002194 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002195 .items = {
2196 { "Mic", 0x0 },
2197 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002198 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002199 },
2200};
2201
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002202#define alc880_lg_lw_modes alc880_threestack_modes
2203
Takashi Iwaid6815182006-03-23 16:06:23 +01002204static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002205 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2206 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2207 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2208 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2209 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2210 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2211 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2212 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2213 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2214 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002215 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2216 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2217 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2218 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002219 {
2220 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2221 .name = "Channel Mode",
2222 .info = alc_ch_mode_info,
2223 .get = alc_ch_mode_get,
2224 .put = alc_ch_mode_put,
2225 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002226 { } /* end */
2227};
2228
2229static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002230 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2231 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2232 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2233
Takashi Iwaid6815182006-03-23 16:06:23 +01002234 /* set capture source to mic-in */
2235 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2236 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2237 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002238 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002239 /* speaker-out */
2240 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2241 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2242 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002243 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2244 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2245 /* mic-in to input */
2246 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2247 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2248 /* built-in mic */
2249 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2250 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2251 /* jack sense */
2252 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2253 { }
2254};
2255
2256/* toggle speaker-output according to the hp-jack state */
2257static void alc880_lg_lw_automute(struct hda_codec *codec)
2258{
2259 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002260 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002261
2262 present = snd_hda_codec_read(codec, 0x1b, 0,
2263 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002264 bits = present ? HDA_AMP_MUTE : 0;
2265 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2266 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002267}
2268
2269static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2270{
2271 /* Looks like the unsol event is incompatible with the standard
2272 * definition. 4bit tag is placed at 28 bit!
2273 */
2274 if ((res >> 28) == 0x01)
2275 alc880_lg_lw_automute(codec);
2276}
2277
Takashi Iwaicb53c622007-08-10 17:21:45 +02002278#ifdef CONFIG_SND_HDA_POWER_SAVE
2279static struct hda_amp_list alc880_loopbacks[] = {
2280 { 0x0b, HDA_INPUT, 0 },
2281 { 0x0b, HDA_INPUT, 1 },
2282 { 0x0b, HDA_INPUT, 2 },
2283 { 0x0b, HDA_INPUT, 3 },
2284 { 0x0b, HDA_INPUT, 4 },
2285 { } /* end */
2286};
2287
2288static struct hda_amp_list alc880_lg_loopbacks[] = {
2289 { 0x0b, HDA_INPUT, 1 },
2290 { 0x0b, HDA_INPUT, 6 },
2291 { 0x0b, HDA_INPUT, 7 },
2292 { } /* end */
2293};
2294#endif
2295
Takashi Iwaid6815182006-03-23 16:06:23 +01002296/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002297 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002298 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300static int alc_init(struct hda_codec *codec)
2301{
2302 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002303 unsigned int i;
2304
2305 for (i = 0; i < spec->num_init_verbs; i++)
2306 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002307
2308 if (spec->init_hook)
2309 spec->init_hook(codec);
2310
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 return 0;
2312}
2313
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002314static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2315{
2316 struct alc_spec *spec = codec->spec;
2317
2318 if (spec->unsol_event)
2319 spec->unsol_event(codec, res);
2320}
2321
Takashi Iwaicb53c622007-08-10 17:21:45 +02002322#ifdef CONFIG_SND_HDA_POWER_SAVE
2323static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2324{
2325 struct alc_spec *spec = codec->spec;
2326 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2327}
2328#endif
2329
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330/*
2331 * Analog playback callbacks
2332 */
2333static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2334 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002335 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336{
2337 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002338 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2339 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340}
2341
2342static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2343 struct hda_codec *codec,
2344 unsigned int stream_tag,
2345 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002346 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347{
2348 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002349 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2350 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351}
2352
2353static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2354 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002355 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356{
2357 struct alc_spec *spec = codec->spec;
2358 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2359}
2360
2361/*
2362 * Digital out
2363 */
2364static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2365 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002366 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367{
2368 struct alc_spec *spec = codec->spec;
2369 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2370}
2371
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002372static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2373 struct hda_codec *codec,
2374 unsigned int stream_tag,
2375 unsigned int format,
2376 struct snd_pcm_substream *substream)
2377{
2378 struct alc_spec *spec = codec->spec;
2379 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2380 stream_tag, format, substream);
2381}
2382
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2384 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002385 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386{
2387 struct alc_spec *spec = codec->spec;
2388 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2389}
2390
2391/*
2392 * Analog capture
2393 */
Takashi Iwai63300792008-01-24 15:31:36 +01002394static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 struct hda_codec *codec,
2396 unsigned int stream_tag,
2397 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002398 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399{
2400 struct alc_spec *spec = codec->spec;
2401
Takashi Iwai63300792008-01-24 15:31:36 +01002402 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 stream_tag, 0, format);
2404 return 0;
2405}
2406
Takashi Iwai63300792008-01-24 15:31:36 +01002407static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002409 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410{
2411 struct alc_spec *spec = codec->spec;
2412
Takashi Iwai888afa12008-03-18 09:57:50 +01002413 snd_hda_codec_cleanup_stream(codec,
2414 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 return 0;
2416}
2417
2418
2419/*
2420 */
2421static struct hda_pcm_stream alc880_pcm_analog_playback = {
2422 .substreams = 1,
2423 .channels_min = 2,
2424 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002425 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 .ops = {
2427 .open = alc880_playback_pcm_open,
2428 .prepare = alc880_playback_pcm_prepare,
2429 .cleanup = alc880_playback_pcm_cleanup
2430 },
2431};
2432
2433static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002434 .substreams = 1,
2435 .channels_min = 2,
2436 .channels_max = 2,
2437 /* NID is set in alc_build_pcms */
2438};
2439
2440static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2441 .substreams = 1,
2442 .channels_min = 2,
2443 .channels_max = 2,
2444 /* NID is set in alc_build_pcms */
2445};
2446
2447static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2448 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 .channels_min = 2,
2450 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002451 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002453 .prepare = alc880_alt_capture_pcm_prepare,
2454 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 },
2456};
2457
2458static struct hda_pcm_stream alc880_pcm_digital_playback = {
2459 .substreams = 1,
2460 .channels_min = 2,
2461 .channels_max = 2,
2462 /* NID is set in alc_build_pcms */
2463 .ops = {
2464 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002465 .close = alc880_dig_playback_pcm_close,
2466 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 },
2468};
2469
2470static struct hda_pcm_stream alc880_pcm_digital_capture = {
2471 .substreams = 1,
2472 .channels_min = 2,
2473 .channels_max = 2,
2474 /* NID is set in alc_build_pcms */
2475};
2476
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002477/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002478static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002479 .substreams = 0,
2480 .channels_min = 0,
2481 .channels_max = 0,
2482};
2483
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484static int alc_build_pcms(struct hda_codec *codec)
2485{
2486 struct alc_spec *spec = codec->spec;
2487 struct hda_pcm *info = spec->pcm_rec;
2488 int i;
2489
2490 codec->num_pcms = 1;
2491 codec->pcm_info = info;
2492
2493 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002494 if (spec->stream_analog_playback) {
2495 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2496 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2497 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2498 }
2499 if (spec->stream_analog_capture) {
2500 snd_assert(spec->adc_nids, return -EINVAL);
2501 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2502 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Takashi Iwai4a471b72005-12-07 13:56:29 +01002505 if (spec->channel_mode) {
2506 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2507 for (i = 0; i < spec->num_channel_mode; i++) {
2508 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2509 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
2512 }
2513
Takashi Iwaie08a0072006-09-07 17:52:14 +02002514 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002516 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002517 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002519 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002520 if (spec->multiout.dig_out_nid &&
2521 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2523 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2524 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002525 if (spec->dig_in_nid &&
2526 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2528 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2529 }
2530 }
2531
Takashi Iwaie08a0072006-09-07 17:52:14 +02002532 /* If the use of more than one ADC is requested for the current
2533 * model, configure a second analog capture-only PCM.
2534 */
2535 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002536 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2537 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002538 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002539 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002540 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002541 if (spec->alt_dac_nid) {
2542 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2543 *spec->stream_analog_alt_playback;
2544 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2545 spec->alt_dac_nid;
2546 } else {
2547 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2548 alc_pcm_null_stream;
2549 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2550 }
2551 if (spec->num_adc_nids > 1) {
2552 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2553 *spec->stream_analog_alt_capture;
2554 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2555 spec->adc_nids[1];
2556 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2557 spec->num_adc_nids - 1;
2558 } else {
2559 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2560 alc_pcm_null_stream;
2561 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002562 }
2563 }
2564
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 return 0;
2566}
2567
2568static void alc_free(struct hda_codec *codec)
2569{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002570 struct alc_spec *spec = codec->spec;
2571 unsigned int i;
2572
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002573 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002574 return;
2575
2576 if (spec->kctl_alloc) {
2577 for (i = 0; i < spec->num_kctl_used; i++)
2578 kfree(spec->kctl_alloc[i].name);
2579 kfree(spec->kctl_alloc);
2580 }
2581 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582}
2583
2584/*
2585 */
2586static struct hda_codec_ops alc_patch_ops = {
2587 .build_controls = alc_build_controls,
2588 .build_pcms = alc_build_pcms,
2589 .init = alc_init,
2590 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002591 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002592#ifdef CONFIG_SND_HDA_POWER_SAVE
2593 .check_power_status = alc_check_power_status,
2594#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595};
2596
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002597
2598/*
2599 * Test configuration for debugging
2600 *
2601 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2602 * enum controls.
2603 */
2604#ifdef CONFIG_SND_DEBUG
2605static hda_nid_t alc880_test_dac_nids[4] = {
2606 0x02, 0x03, 0x04, 0x05
2607};
2608
2609static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002610 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002611 .items = {
2612 { "In-1", 0x0 },
2613 { "In-2", 0x1 },
2614 { "In-3", 0x2 },
2615 { "In-4", 0x3 },
2616 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002617 { "Front", 0x5 },
2618 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002619 },
2620};
2621
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002622static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002623 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002624 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002625 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002626 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002627};
2628
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002629static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2630 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002631{
2632 static char *texts[] = {
2633 "N/A", "Line Out", "HP Out",
2634 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2635 };
2636 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2637 uinfo->count = 1;
2638 uinfo->value.enumerated.items = 8;
2639 if (uinfo->value.enumerated.item >= 8)
2640 uinfo->value.enumerated.item = 7;
2641 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2642 return 0;
2643}
2644
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002645static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2646 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002647{
2648 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2649 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2650 unsigned int pin_ctl, item = 0;
2651
2652 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2653 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2654 if (pin_ctl & AC_PINCTL_OUT_EN) {
2655 if (pin_ctl & AC_PINCTL_HP_EN)
2656 item = 2;
2657 else
2658 item = 1;
2659 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2660 switch (pin_ctl & AC_PINCTL_VREFEN) {
2661 case AC_PINCTL_VREF_HIZ: item = 3; break;
2662 case AC_PINCTL_VREF_50: item = 4; break;
2663 case AC_PINCTL_VREF_GRD: item = 5; break;
2664 case AC_PINCTL_VREF_80: item = 6; break;
2665 case AC_PINCTL_VREF_100: item = 7; break;
2666 }
2667 }
2668 ucontrol->value.enumerated.item[0] = item;
2669 return 0;
2670}
2671
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002672static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2673 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002674{
2675 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2676 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2677 static unsigned int ctls[] = {
2678 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2679 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2680 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2681 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2682 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2683 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2684 };
2685 unsigned int old_ctl, new_ctl;
2686
2687 old_ctl = snd_hda_codec_read(codec, nid, 0,
2688 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2689 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2690 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002691 int val;
2692 snd_hda_codec_write_cache(codec, nid, 0,
2693 AC_VERB_SET_PIN_WIDGET_CONTROL,
2694 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002695 val = ucontrol->value.enumerated.item[0] >= 3 ?
2696 HDA_AMP_MUTE : 0;
2697 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2698 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002699 return 1;
2700 }
2701 return 0;
2702}
2703
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002704static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2705 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002706{
2707 static char *texts[] = {
2708 "Front", "Surround", "CLFE", "Side"
2709 };
2710 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2711 uinfo->count = 1;
2712 uinfo->value.enumerated.items = 4;
2713 if (uinfo->value.enumerated.item >= 4)
2714 uinfo->value.enumerated.item = 3;
2715 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2716 return 0;
2717}
2718
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002719static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2720 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002721{
2722 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2723 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2724 unsigned int sel;
2725
2726 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2727 ucontrol->value.enumerated.item[0] = sel & 3;
2728 return 0;
2729}
2730
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002731static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2732 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002733{
2734 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2735 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2736 unsigned int sel;
2737
2738 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2739 if (ucontrol->value.enumerated.item[0] != sel) {
2740 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002741 snd_hda_codec_write_cache(codec, nid, 0,
2742 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002743 return 1;
2744 }
2745 return 0;
2746}
2747
2748#define PIN_CTL_TEST(xname,nid) { \
2749 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2750 .name = xname, \
2751 .info = alc_test_pin_ctl_info, \
2752 .get = alc_test_pin_ctl_get, \
2753 .put = alc_test_pin_ctl_put, \
2754 .private_value = nid \
2755 }
2756
2757#define PIN_SRC_TEST(xname,nid) { \
2758 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2759 .name = xname, \
2760 .info = alc_test_pin_src_info, \
2761 .get = alc_test_pin_src_get, \
2762 .put = alc_test_pin_src_put, \
2763 .private_value = nid \
2764 }
2765
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002766static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002767 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2768 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2769 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2770 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002771 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2772 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2773 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2774 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002775 PIN_CTL_TEST("Front Pin Mode", 0x14),
2776 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2777 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2778 PIN_CTL_TEST("Side Pin Mode", 0x17),
2779 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2780 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2781 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2782 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2783 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2784 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2785 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2786 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2787 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2788 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2789 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2790 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2791 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2792 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2793 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2794 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2795 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2796 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002797 {
2798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2799 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002800 .info = alc_ch_mode_info,
2801 .get = alc_ch_mode_get,
2802 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002803 },
2804 { } /* end */
2805};
2806
2807static struct hda_verb alc880_test_init_verbs[] = {
2808 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002809 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2810 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2811 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2812 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2813 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2814 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2815 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2816 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002817 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002818 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2819 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2820 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2821 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002822 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002823 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2824 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2825 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2826 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002827 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002828 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2829 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2831 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002832 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002833 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2834 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002835 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2837 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002838 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002839 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2840 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2841 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2842 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002843 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002844 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002845 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002847 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002848 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002849 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002850 /* Analog input/passthru */
2851 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2852 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2853 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2854 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2855 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002856 { }
2857};
2858#endif
2859
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860/*
2861 */
2862
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002863static const char *alc880_models[ALC880_MODEL_LAST] = {
2864 [ALC880_3ST] = "3stack",
2865 [ALC880_TCL_S700] = "tcl",
2866 [ALC880_3ST_DIG] = "3stack-digout",
2867 [ALC880_CLEVO] = "clevo",
2868 [ALC880_5ST] = "5stack",
2869 [ALC880_5ST_DIG] = "5stack-digout",
2870 [ALC880_W810] = "w810",
2871 [ALC880_Z71V] = "z71v",
2872 [ALC880_6ST] = "6stack",
2873 [ALC880_6ST_DIG] = "6stack-digout",
2874 [ALC880_ASUS] = "asus",
2875 [ALC880_ASUS_W1V] = "asus-w1v",
2876 [ALC880_ASUS_DIG] = "asus-dig",
2877 [ALC880_ASUS_DIG2] = "asus-dig2",
2878 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002879 [ALC880_UNIWILL_P53] = "uniwill-p53",
2880 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002881 [ALC880_F1734] = "F1734",
2882 [ALC880_LG] = "lg",
2883 [ALC880_LG_LW] = "lg-lw",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002884#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002885 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002886#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002887 [ALC880_AUTO] = "auto",
2888};
2889
2890static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002891 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002892 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2893 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2894 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2895 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2896 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2897 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2898 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2899 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002900 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2901 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002902 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2903 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2904 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2905 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2906 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2907 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2908 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2909 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2910 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2911 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Tobin Davis0e4ceb72007-01-08 10:54:26 +01002912 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002913 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2914 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2915 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002916 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002917 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002918 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2919 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002920 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2921 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002922 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2923 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2924 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2925 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002926 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2927 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002928 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002929 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002930 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002931 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002932 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2933 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002934 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2935 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002936 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002937 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002938 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002939 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002940 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002941 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2942 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002943 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002944 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2945 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
2946 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2947 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002948 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2949 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002950 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002951 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002952 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2953 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002954 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2955 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2956 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002957 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
2958 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2959 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 {}
2961};
2962
Takashi Iwai16ded522005-06-10 19:58:24 +02002963/*
Kailang Yangdf694da2005-12-05 19:42:22 +01002964 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02002965 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002966static struct alc_config_preset alc880_presets[] = {
2967 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002968 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002969 .init_verbs = { alc880_volume_init_verbs,
2970 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002971 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002972 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002973 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2974 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002975 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002976 .input_mux = &alc880_capture_source,
2977 },
2978 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002979 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002980 .init_verbs = { alc880_volume_init_verbs,
2981 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002982 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002983 .dac_nids = alc880_dac_nids,
2984 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002985 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2986 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002987 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002988 .input_mux = &alc880_capture_source,
2989 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002990 [ALC880_TCL_S700] = {
2991 .mixers = { alc880_tcl_s700_mixer },
2992 .init_verbs = { alc880_volume_init_verbs,
2993 alc880_pin_tcl_S700_init_verbs,
2994 alc880_gpio2_init_verbs },
2995 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2996 .dac_nids = alc880_dac_nids,
2997 .hp_nid = 0x03,
2998 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2999 .channel_mode = alc880_2_jack_modes,
3000 .input_mux = &alc880_capture_source,
3001 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003002 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003003 .mixers = { alc880_three_stack_mixer,
3004 alc880_five_stack_mixer},
3005 .init_verbs = { alc880_volume_init_verbs,
3006 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003007 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3008 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003009 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3010 .channel_mode = alc880_fivestack_modes,
3011 .input_mux = &alc880_capture_source,
3012 },
3013 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003014 .mixers = { alc880_three_stack_mixer,
3015 alc880_five_stack_mixer },
3016 .init_verbs = { alc880_volume_init_verbs,
3017 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003018 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3019 .dac_nids = alc880_dac_nids,
3020 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003021 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3022 .channel_mode = alc880_fivestack_modes,
3023 .input_mux = &alc880_capture_source,
3024 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003025 [ALC880_6ST] = {
3026 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003027 .init_verbs = { alc880_volume_init_verbs,
3028 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003029 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3030 .dac_nids = alc880_6st_dac_nids,
3031 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3032 .channel_mode = alc880_sixstack_modes,
3033 .input_mux = &alc880_6stack_capture_source,
3034 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003035 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003036 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003037 .init_verbs = { alc880_volume_init_verbs,
3038 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003039 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3040 .dac_nids = alc880_6st_dac_nids,
3041 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003042 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3043 .channel_mode = alc880_sixstack_modes,
3044 .input_mux = &alc880_6stack_capture_source,
3045 },
3046 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003047 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003048 .init_verbs = { alc880_volume_init_verbs,
3049 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003050 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003051 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3052 .dac_nids = alc880_w810_dac_nids,
3053 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003054 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3055 .channel_mode = alc880_w810_modes,
3056 .input_mux = &alc880_capture_source,
3057 },
3058 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003059 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003060 .init_verbs = { alc880_volume_init_verbs,
3061 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003062 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3063 .dac_nids = alc880_z71v_dac_nids,
3064 .dig_out_nid = ALC880_DIGOUT_NID,
3065 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003066 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3067 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003068 .input_mux = &alc880_capture_source,
3069 },
3070 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003071 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003072 .init_verbs = { alc880_volume_init_verbs,
3073 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003074 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3075 .dac_nids = alc880_f1734_dac_nids,
3076 .hp_nid = 0x02,
3077 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3078 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003079 .input_mux = &alc880_f1734_capture_source,
3080 .unsol_event = alc880_uniwill_p53_unsol_event,
3081 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003082 },
3083 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003084 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003085 .init_verbs = { alc880_volume_init_verbs,
3086 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003087 alc880_gpio1_init_verbs },
3088 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3089 .dac_nids = alc880_asus_dac_nids,
3090 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3091 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003092 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003093 .input_mux = &alc880_capture_source,
3094 },
3095 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003096 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003097 .init_verbs = { alc880_volume_init_verbs,
3098 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003099 alc880_gpio1_init_verbs },
3100 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3101 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003102 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003103 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3104 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003105 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003106 .input_mux = &alc880_capture_source,
3107 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003108 [ALC880_ASUS_DIG2] = {
3109 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003110 .init_verbs = { alc880_volume_init_verbs,
3111 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003112 alc880_gpio2_init_verbs }, /* use GPIO2 */
3113 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3114 .dac_nids = alc880_asus_dac_nids,
3115 .dig_out_nid = ALC880_DIGOUT_NID,
3116 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3117 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003118 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003119 .input_mux = &alc880_capture_source,
3120 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003121 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003122 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003123 .init_verbs = { alc880_volume_init_verbs,
3124 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003125 alc880_gpio1_init_verbs },
3126 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3127 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003128 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003129 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3130 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003131 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003132 .input_mux = &alc880_capture_source,
3133 },
3134 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003135 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003136 .init_verbs = { alc880_volume_init_verbs,
3137 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003138 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3139 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003140 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003141 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3142 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003143 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003144 .input_mux = &alc880_capture_source,
3145 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003146 [ALC880_UNIWILL] = {
3147 .mixers = { alc880_uniwill_mixer },
3148 .init_verbs = { alc880_volume_init_verbs,
3149 alc880_uniwill_init_verbs },
3150 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3151 .dac_nids = alc880_asus_dac_nids,
3152 .dig_out_nid = ALC880_DIGOUT_NID,
3153 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3154 .channel_mode = alc880_threestack_modes,
3155 .need_dac_fix = 1,
3156 .input_mux = &alc880_capture_source,
3157 .unsol_event = alc880_uniwill_unsol_event,
3158 .init_hook = alc880_uniwill_automute,
3159 },
3160 [ALC880_UNIWILL_P53] = {
3161 .mixers = { alc880_uniwill_p53_mixer },
3162 .init_verbs = { alc880_volume_init_verbs,
3163 alc880_uniwill_p53_init_verbs },
3164 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3165 .dac_nids = alc880_asus_dac_nids,
3166 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003167 .channel_mode = alc880_threestack_modes,
3168 .input_mux = &alc880_capture_source,
3169 .unsol_event = alc880_uniwill_p53_unsol_event,
3170 .init_hook = alc880_uniwill_p53_hp_automute,
3171 },
3172 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003173 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003174 alc880_pcbeep_mixer, },
3175 .init_verbs = { alc880_volume_init_verbs,
3176 alc880_uniwill_p53_init_verbs,
3177 alc880_beep_init_verbs },
3178 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3179 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003180 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003181 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3182 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003183 .input_mux = &alc880_capture_source,
3184 .unsol_event = alc880_uniwill_p53_unsol_event,
3185 .init_hook = alc880_uniwill_p53_hp_automute,
3186 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003187 [ALC880_CLEVO] = {
3188 .mixers = { alc880_three_stack_mixer },
3189 .init_verbs = { alc880_volume_init_verbs,
3190 alc880_pin_clevo_init_verbs },
3191 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3192 .dac_nids = alc880_dac_nids,
3193 .hp_nid = 0x03,
3194 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3195 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003196 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003197 .input_mux = &alc880_capture_source,
3198 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003199 [ALC880_LG] = {
3200 .mixers = { alc880_lg_mixer },
3201 .init_verbs = { alc880_volume_init_verbs,
3202 alc880_lg_init_verbs },
3203 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3204 .dac_nids = alc880_lg_dac_nids,
3205 .dig_out_nid = ALC880_DIGOUT_NID,
3206 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3207 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003208 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003209 .input_mux = &alc880_lg_capture_source,
3210 .unsol_event = alc880_lg_unsol_event,
3211 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003212#ifdef CONFIG_SND_HDA_POWER_SAVE
3213 .loopbacks = alc880_lg_loopbacks,
3214#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003215 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003216 [ALC880_LG_LW] = {
3217 .mixers = { alc880_lg_lw_mixer },
3218 .init_verbs = { alc880_volume_init_verbs,
3219 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003220 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003221 .dac_nids = alc880_dac_nids,
3222 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003223 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3224 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003225 .input_mux = &alc880_lg_lw_capture_source,
3226 .unsol_event = alc880_lg_lw_unsol_event,
3227 .init_hook = alc880_lg_lw_automute,
3228 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003229#ifdef CONFIG_SND_DEBUG
3230 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003231 .mixers = { alc880_test_mixer },
3232 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003233 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3234 .dac_nids = alc880_test_dac_nids,
3235 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003236 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3237 .channel_mode = alc880_test_modes,
3238 .input_mux = &alc880_test_capture_source,
3239 },
3240#endif
3241};
3242
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003243/*
3244 * Automatic parse of I/O pins from the BIOS configuration
3245 */
3246
3247#define NUM_CONTROL_ALLOC 32
3248#define NUM_VERB_ALLOC 32
3249
3250enum {
3251 ALC_CTL_WIDGET_VOL,
3252 ALC_CTL_WIDGET_MUTE,
3253 ALC_CTL_BIND_MUTE,
3254};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003255static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003256 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3257 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003258 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003259};
3260
3261/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003262static int add_control(struct alc_spec *spec, int type, const char *name,
3263 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003264{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003265 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003266
3267 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3268 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3269
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003270 /* array + terminator */
3271 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3272 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003273 return -ENOMEM;
3274 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003275 memcpy(knew, spec->kctl_alloc,
3276 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003277 kfree(spec->kctl_alloc);
3278 }
3279 spec->kctl_alloc = knew;
3280 spec->num_kctl_alloc = num;
3281 }
3282
3283 knew = &spec->kctl_alloc[spec->num_kctl_used];
3284 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003285 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003286 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003287 return -ENOMEM;
3288 knew->private_value = val;
3289 spec->num_kctl_used++;
3290 return 0;
3291}
3292
3293#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3294#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3295#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3296#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3297#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3298#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3299#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3300#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3301#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3302#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3303#define ALC880_PIN_CD_NID 0x1c
3304
3305/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003306static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3307 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003308{
3309 hda_nid_t nid;
3310 int assigned[4];
3311 int i, j;
3312
3313 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003314 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003315
3316 /* check the pins hardwired to audio widget */
3317 for (i = 0; i < cfg->line_outs; i++) {
3318 nid = cfg->line_out_pins[i];
3319 if (alc880_is_fixed_pin(nid)) {
3320 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003321 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003322 assigned[idx] = 1;
3323 }
3324 }
3325 /* left pins can be connect to any audio widget */
3326 for (i = 0; i < cfg->line_outs; i++) {
3327 nid = cfg->line_out_pins[i];
3328 if (alc880_is_fixed_pin(nid))
3329 continue;
3330 /* search for an empty channel */
3331 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003332 if (!assigned[j]) {
3333 spec->multiout.dac_nids[i] =
3334 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003335 assigned[j] = 1;
3336 break;
3337 }
3338 }
3339 }
3340 spec->multiout.num_dacs = cfg->line_outs;
3341 return 0;
3342}
3343
3344/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003345static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3346 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003347{
3348 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003349 static const char *chname[4] = {
3350 "Front", "Surround", NULL /*CLFE*/, "Side"
3351 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003352 hda_nid_t nid;
3353 int i, err;
3354
3355 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003356 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003357 continue;
3358 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3359 if (i == 2) {
3360 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003361 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3362 "Center Playback Volume",
3363 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3364 HDA_OUTPUT));
3365 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003366 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003367 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3368 "LFE Playback Volume",
3369 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3370 HDA_OUTPUT));
3371 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003372 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003373 err = add_control(spec, ALC_CTL_BIND_MUTE,
3374 "Center Playback Switch",
3375 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3376 HDA_INPUT));
3377 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003378 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003379 err = add_control(spec, ALC_CTL_BIND_MUTE,
3380 "LFE Playback Switch",
3381 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3382 HDA_INPUT));
3383 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003384 return err;
3385 } else {
3386 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003387 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3388 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3389 HDA_OUTPUT));
3390 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003391 return err;
3392 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003393 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3394 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3395 HDA_INPUT));
3396 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003397 return err;
3398 }
3399 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003400 return 0;
3401}
3402
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003403/* add playback controls for speaker and HP outputs */
3404static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3405 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003406{
3407 hda_nid_t nid;
3408 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003409 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003410
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003411 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003412 return 0;
3413
3414 if (alc880_is_fixed_pin(pin)) {
3415 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003416 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003417 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003418 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003419 else
3420 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003421 /* control HP volume/switch on the output mixer amp */
3422 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003423 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003424 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3425 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3426 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003427 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003428 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003429 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3430 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3431 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003432 return err;
3433 } else if (alc880_is_multi_pin(pin)) {
3434 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003435 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003436 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003437 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3438 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3439 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003440 return err;
3441 }
3442 return 0;
3443}
3444
3445/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003446static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3447 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003448 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003449{
3450 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003451 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003452
3453 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003454 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3455 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3456 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003457 return err;
3458 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003459 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3460 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3461 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003462 return err;
3463 return 0;
3464}
3465
3466/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003467static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3468 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003469{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003470 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003471 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003472
3473 for (i = 0; i < AUTO_PIN_LAST; i++) {
3474 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003475 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003476 err = new_analog_input(spec, cfg->input_pins[i],
3477 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003478 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003479 if (err < 0)
3480 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003481 imux->items[imux->num_items].label =
3482 auto_pin_cfg_labels[i];
3483 imux->items[imux->num_items].index =
3484 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003485 imux->num_items++;
3486 }
3487 }
3488 return 0;
3489}
3490
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003491static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3492 unsigned int pin_type)
3493{
3494 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3495 pin_type);
3496 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003497 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3498 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003499}
3500
Kailang Yangdf694da2005-12-05 19:42:22 +01003501static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3502 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003503 int dac_idx)
3504{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003505 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003506 /* need the manual connection? */
3507 if (alc880_is_multi_pin(nid)) {
3508 struct alc_spec *spec = codec->spec;
3509 int idx = alc880_multi_pin_idx(nid);
3510 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3511 AC_VERB_SET_CONNECT_SEL,
3512 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3513 }
3514}
3515
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003516static int get_pin_type(int line_out_type)
3517{
3518 if (line_out_type == AUTO_PIN_HP_OUT)
3519 return PIN_HP;
3520 else
3521 return PIN_OUT;
3522}
3523
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003524static void alc880_auto_init_multi_out(struct hda_codec *codec)
3525{
3526 struct alc_spec *spec = codec->spec;
3527 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003528
3529 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003530 for (i = 0; i < spec->autocfg.line_outs; i++) {
3531 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003532 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3533 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003534 }
3535}
3536
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003537static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003538{
3539 struct alc_spec *spec = codec->spec;
3540 hda_nid_t pin;
3541
Takashi Iwai82bc9552006-03-21 11:24:42 +01003542 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003543 if (pin) /* connect to front */
3544 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003545 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003546 if (pin) /* connect to front */
3547 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3548}
3549
3550static void alc880_auto_init_analog_input(struct hda_codec *codec)
3551{
3552 struct alc_spec *spec = codec->spec;
3553 int i;
3554
3555 for (i = 0; i < AUTO_PIN_LAST; i++) {
3556 hda_nid_t nid = spec->autocfg.input_pins[i];
3557 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003558 snd_hda_codec_write(codec, nid, 0,
3559 AC_VERB_SET_PIN_WIDGET_CONTROL,
3560 i <= AUTO_PIN_FRONT_MIC ?
3561 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003562 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003563 snd_hda_codec_write(codec, nid, 0,
3564 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003565 AMP_OUT_MUTE);
3566 }
3567 }
3568}
3569
3570/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003571/* return 1 if successful, 0 if the proper config is not found,
3572 * or a negative error code
3573 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003574static int alc880_parse_auto_config(struct hda_codec *codec)
3575{
3576 struct alc_spec *spec = codec->spec;
3577 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003578 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003579
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003580 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3581 alc880_ignore);
3582 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003583 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003584 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003585 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003586
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003587 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3588 if (err < 0)
3589 return err;
3590 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3591 if (err < 0)
3592 return err;
3593 err = alc880_auto_create_extra_out(spec,
3594 spec->autocfg.speaker_pins[0],
3595 "Speaker");
3596 if (err < 0)
3597 return err;
3598 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3599 "Headphone");
3600 if (err < 0)
3601 return err;
3602 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3603 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003604 return err;
3605
3606 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3607
3608 if (spec->autocfg.dig_out_pin)
3609 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3610 if (spec->autocfg.dig_in_pin)
3611 spec->dig_in_nid = ALC880_DIGIN_NID;
3612
3613 if (spec->kctl_alloc)
3614 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3615
3616 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3617
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003618 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003619 spec->input_mux = &spec->private_imux;
3620
3621 return 1;
3622}
3623
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003624/* additional initialization for auto-configuration model */
3625static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003626{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003627 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003628 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003629 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003630 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003631 if (spec->unsol_event)
3632 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003633}
3634
3635/*
3636 * OK, here we have finally the patch for ALC880
3637 */
3638
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639static int patch_alc880(struct hda_codec *codec)
3640{
3641 struct alc_spec *spec;
3642 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003643 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003645 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 if (spec == NULL)
3647 return -ENOMEM;
3648
3649 codec->spec = spec;
3650
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003651 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3652 alc880_models,
3653 alc880_cfg_tbl);
3654 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003655 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3656 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003657 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 }
3659
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003660 if (board_config == ALC880_AUTO) {
3661 /* automatic parse from the BIOS config */
3662 err = alc880_parse_auto_config(codec);
3663 if (err < 0) {
3664 alc_free(codec);
3665 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003666 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003667 printk(KERN_INFO
3668 "hda_codec: Cannot set up configuration "
3669 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003670 board_config = ALC880_3ST;
3671 }
3672 }
3673
Kailang Yangdf694da2005-12-05 19:42:22 +01003674 if (board_config != ALC880_AUTO)
3675 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
3677 spec->stream_name_analog = "ALC880 Analog";
3678 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3679 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003680 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
3682 spec->stream_name_digital = "ALC880 Digital";
3683 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3684 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3685
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003686 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003687 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003688 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003689 /* get type */
3690 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003691 if (wcap != AC_WID_AUD_IN) {
3692 spec->adc_nids = alc880_adc_nids_alt;
3693 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003694 spec->mixers[spec->num_mixers] =
3695 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003696 spec->num_mixers++;
3697 } else {
3698 spec->adc_nids = alc880_adc_nids;
3699 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3700 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3701 spec->num_mixers++;
3702 }
3703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704
Takashi Iwai2134ea42008-01-10 16:53:55 +01003705 spec->vmaster_nid = 0x0c;
3706
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003708 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003709 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003710#ifdef CONFIG_SND_HDA_POWER_SAVE
3711 if (!spec->loopback.amplist)
3712 spec->loopback.amplist = alc880_loopbacks;
3713#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
3715 return 0;
3716}
3717
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003718
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719/*
3720 * ALC260 support
3721 */
3722
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003723static hda_nid_t alc260_dac_nids[1] = {
3724 /* front */
3725 0x02,
3726};
3727
3728static hda_nid_t alc260_adc_nids[1] = {
3729 /* ADC0 */
3730 0x04,
3731};
3732
Kailang Yangdf694da2005-12-05 19:42:22 +01003733static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003734 /* ADC1 */
3735 0x05,
3736};
3737
Kailang Yangdf694da2005-12-05 19:42:22 +01003738static hda_nid_t alc260_hp_adc_nids[2] = {
3739 /* ADC1, 0 */
3740 0x05, 0x04
3741};
3742
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003743/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3744 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3745 */
3746static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003747 /* ADC0, ADC1 */
3748 0x04, 0x05
3749};
3750
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003751#define ALC260_DIGOUT_NID 0x03
3752#define ALC260_DIGIN_NID 0x06
3753
3754static struct hda_input_mux alc260_capture_source = {
3755 .num_items = 4,
3756 .items = {
3757 { "Mic", 0x0 },
3758 { "Front Mic", 0x1 },
3759 { "Line", 0x2 },
3760 { "CD", 0x4 },
3761 },
3762};
3763
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003764/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003765 * headphone jack and the internal CD lines since these are the only pins at
3766 * which audio can appear. For flexibility, also allow the option of
3767 * recording the mixer output on the second ADC (ADC0 doesn't have a
3768 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003769 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003770static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3771 {
3772 .num_items = 3,
3773 .items = {
3774 { "Mic/Line", 0x0 },
3775 { "CD", 0x4 },
3776 { "Headphone", 0x2 },
3777 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003778 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003779 {
3780 .num_items = 4,
3781 .items = {
3782 { "Mic/Line", 0x0 },
3783 { "CD", 0x4 },
3784 { "Headphone", 0x2 },
3785 { "Mixer", 0x5 },
3786 },
3787 },
3788
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003789};
3790
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003791/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3792 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003793 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003794static struct hda_input_mux alc260_acer_capture_sources[2] = {
3795 {
3796 .num_items = 4,
3797 .items = {
3798 { "Mic", 0x0 },
3799 { "Line", 0x2 },
3800 { "CD", 0x4 },
3801 { "Headphone", 0x5 },
3802 },
3803 },
3804 {
3805 .num_items = 5,
3806 .items = {
3807 { "Mic", 0x0 },
3808 { "Line", 0x2 },
3809 { "CD", 0x4 },
3810 { "Headphone", 0x6 },
3811 { "Mixer", 0x5 },
3812 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003813 },
3814};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815/*
3816 * This is just place-holder, so there's something for alc_build_pcms to look
3817 * at when it calculates the maximum number of channels. ALC260 has no mixer
3818 * element which allows changing the channel mode, so the verb list is
3819 * never used.
3820 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003821static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 { 2, NULL },
3823};
3824
Kailang Yangdf694da2005-12-05 19:42:22 +01003825
3826/* Mixer combinations
3827 *
3828 * basic: base_output + input + pc_beep + capture
3829 * HP: base_output + input + capture_alt
3830 * HP_3013: hp_3013 + input + capture
3831 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003832 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003833 */
3834
3835static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003836 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003837 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003838 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3839 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3840 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3841 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3842 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003843};
Kailang Yangdf694da2005-12-05 19:42:22 +01003844
3845static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3847 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3848 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3849 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3850 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3851 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3852 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3853 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 { } /* end */
3855};
3856
Kailang Yangdf694da2005-12-05 19:42:22 +01003857static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3858 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3859 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3860 { } /* end */
3861};
3862
Takashi Iwaibec15c32008-01-28 18:16:30 +01003863/* update HP, line and mono out pins according to the master switch */
3864static void alc260_hp_master_update(struct hda_codec *codec,
3865 hda_nid_t hp, hda_nid_t line,
3866 hda_nid_t mono)
3867{
3868 struct alc_spec *spec = codec->spec;
3869 unsigned int val = spec->master_sw ? PIN_HP : 0;
3870 /* change HP and line-out pins */
3871 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3872 val);
3873 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3874 val);
3875 /* mono (speaker) depending on the HP jack sense */
3876 val = (val && !spec->jack_present) ? PIN_OUT : 0;
3877 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3878 val);
3879}
3880
3881static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
3882 struct snd_ctl_elem_value *ucontrol)
3883{
3884 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3885 struct alc_spec *spec = codec->spec;
3886 *ucontrol->value.integer.value = spec->master_sw;
3887 return 0;
3888}
3889
3890static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
3891 struct snd_ctl_elem_value *ucontrol)
3892{
3893 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3894 struct alc_spec *spec = codec->spec;
3895 int val = !!*ucontrol->value.integer.value;
3896 hda_nid_t hp, line, mono;
3897
3898 if (val == spec->master_sw)
3899 return 0;
3900 spec->master_sw = val;
3901 hp = (kcontrol->private_value >> 16) & 0xff;
3902 line = (kcontrol->private_value >> 8) & 0xff;
3903 mono = kcontrol->private_value & 0xff;
3904 alc260_hp_master_update(codec, hp, line, mono);
3905 return 1;
3906}
3907
3908static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
3909 {
3910 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3911 .name = "Master Playback Switch",
3912 .info = snd_ctl_boolean_mono_info,
3913 .get = alc260_hp_master_sw_get,
3914 .put = alc260_hp_master_sw_put,
3915 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
3916 },
3917 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3918 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
3919 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3920 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3921 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
3922 HDA_OUTPUT),
3923 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3924 { } /* end */
3925};
3926
3927static struct hda_verb alc260_hp_unsol_verbs[] = {
3928 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3929 {},
3930};
3931
3932static void alc260_hp_automute(struct hda_codec *codec)
3933{
3934 struct alc_spec *spec = codec->spec;
3935 unsigned int present;
3936
3937 present = snd_hda_codec_read(codec, 0x10, 0,
3938 AC_VERB_GET_PIN_SENSE, 0);
3939 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3940 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
3941}
3942
3943static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3944{
3945 if ((res >> 26) == ALC880_HP_EVENT)
3946 alc260_hp_automute(codec);
3947}
3948
Kailang Yangdf694da2005-12-05 19:42:22 +01003949static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01003950 {
3951 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3952 .name = "Master Playback Switch",
3953 .info = snd_ctl_boolean_mono_info,
3954 .get = alc260_hp_master_sw_get,
3955 .put = alc260_hp_master_sw_put,
3956 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
3957 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003958 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3959 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3960 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
3961 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
3962 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3963 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01003964 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3965 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003966 { } /* end */
3967};
3968
Takashi Iwaibec15c32008-01-28 18:16:30 +01003969static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
3970 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3971 {},
3972};
3973
3974static void alc260_hp_3013_automute(struct hda_codec *codec)
3975{
3976 struct alc_spec *spec = codec->spec;
3977 unsigned int present;
3978
3979 present = snd_hda_codec_read(codec, 0x15, 0,
3980 AC_VERB_GET_PIN_SENSE, 0);
3981 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3982 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
3983}
3984
3985static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
3986 unsigned int res)
3987{
3988 if ((res >> 26) == ALC880_HP_EVENT)
3989 alc260_hp_3013_automute(codec);
3990}
3991
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003992/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
3993 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
3994 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003995static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003996 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003997 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003998 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003999 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4000 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4001 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4002 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004003 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004004 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4005 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004006 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4007 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004008 { } /* end */
4009};
4010
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004011/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4012 * versions of the ALC260 don't act on requests to enable mic bias from NID
4013 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4014 * datasheet doesn't mention this restriction. At this stage it's not clear
4015 * whether this behaviour is intentional or is a hardware bug in chip
4016 * revisions available in early 2006. Therefore for now allow the
4017 * "Headphone Jack Mode" control to span all choices, but if it turns out
4018 * that the lack of mic bias for this NID is intentional we could change the
4019 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4020 *
4021 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4022 * don't appear to make the mic bias available from the "line" jack, even
4023 * though the NID used for this jack (0x14) can supply it. The theory is
4024 * that perhaps Acer have included blocking capacitors between the ALC260
4025 * and the output jack. If this turns out to be the case for all such
4026 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4027 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004028 *
4029 * The C20x Tablet series have a mono internal speaker which is controlled
4030 * via the chip's Mono sum widget and pin complex, so include the necessary
4031 * controls for such models. On models without a "mono speaker" the control
4032 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004033 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004034static struct snd_kcontrol_new alc260_acer_mixer[] = {
4035 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4036 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004037 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004038 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004039 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004040 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004041 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004042 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4043 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4044 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4045 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4046 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4047 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4048 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4049 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4050 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4051 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4052 { } /* end */
4053};
4054
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004055/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4056 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4057 */
4058static struct snd_kcontrol_new alc260_will_mixer[] = {
4059 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4060 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4061 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4062 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4063 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4064 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4065 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4066 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4067 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4068 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4069 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4070 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4071 { } /* end */
4072};
4073
4074/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4075 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4076 */
4077static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4078 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4079 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4080 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4081 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4082 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4083 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4084 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4085 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4086 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4087 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4088 { } /* end */
4089};
4090
Kailang Yangdf694da2005-12-05 19:42:22 +01004091/* capture mixer elements */
4092static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004093 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4094 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004095 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4096 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004097 {
4098 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004099 /* The multiple "Capture Source" controls confuse alsamixer
4100 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004101 */
4102 /* .name = "Capture Source", */
4103 .name = "Input Source",
4104 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004105 .info = alc_mux_enum_info,
4106 .get = alc_mux_enum_get,
4107 .put = alc_mux_enum_put,
4108 },
4109 { } /* end */
4110};
4111
Kailang Yangdf694da2005-12-05 19:42:22 +01004112static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4113 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4114 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4115 {
4116 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4117 /* The multiple "Capture Source" controls confuse alsamixer
4118 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004119 */
4120 /* .name = "Capture Source", */
4121 .name = "Input Source",
4122 .count = 1,
4123 .info = alc_mux_enum_info,
4124 .get = alc_mux_enum_get,
4125 .put = alc_mux_enum_put,
4126 },
4127 { } /* end */
4128};
4129
4130/*
4131 * initialization verbs
4132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133static struct hda_verb alc260_init_verbs[] = {
4134 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004135 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004137 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004139 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004141 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004143 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004145 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004147 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004149 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004151 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4152 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004153 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 /* set connection select to line in (default select for this ADC) */
4155 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004156 /* mute capture amp left and right */
4157 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4158 /* set connection select to line in (default select for this ADC) */
4159 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004160 /* set vol=0 Line-Out mixer amp left and right */
4161 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4162 /* unmute pin widget amp left and right (no gain on this amp) */
4163 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4164 /* set vol=0 HP mixer amp left and right */
4165 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4166 /* unmute pin widget amp left and right (no gain on this amp) */
4167 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4168 /* set vol=0 Mono mixer amp left and right */
4169 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4170 /* unmute pin widget amp left and right (no gain on this amp) */
4171 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4172 /* unmute LINE-2 out pin */
4173 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004174 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4175 * Line In 2 = 0x03
4176 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004177 /* mute analog inputs */
4178 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4179 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4180 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4181 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4182 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004184 /* mute Front out path */
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 /* mute Headphone out path */
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 /* mute Mono out path */
4191 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4192 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 { }
4194};
4195
Takashi Iwai474167d2006-05-17 17:17:43 +02004196#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004197static struct hda_verb alc260_hp_init_verbs[] = {
4198 /* Headphone and output */
4199 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4200 /* mono output */
4201 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4202 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4203 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4204 /* Mic2 (front panel) pin widget for input and vref at 80% */
4205 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4206 /* Line In pin widget for input */
4207 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4208 /* Line-2 pin widget for output */
4209 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4210 /* CD pin widget for input */
4211 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4212 /* unmute amp left and right */
4213 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4214 /* set connection select to line in (default select for this ADC) */
4215 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4216 /* unmute Line-Out mixer amp left and right (volume = 0) */
4217 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4218 /* mute pin widget amp left and right (no gain on this amp) */
4219 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4220 /* unmute HP mixer amp left and right (volume = 0) */
4221 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4222 /* mute pin widget amp left and right (no gain on this amp) */
4223 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004224 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4225 * Line In 2 = 0x03
4226 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004227 /* mute analog inputs */
4228 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4229 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4230 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4231 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4232 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004233 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4234 /* Unmute Front out path */
4235 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4236 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4237 /* Unmute Headphone out path */
4238 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4239 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4240 /* Unmute Mono out path */
4241 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4242 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4243 { }
4244};
Takashi Iwai474167d2006-05-17 17:17:43 +02004245#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004246
4247static struct hda_verb alc260_hp_3013_init_verbs[] = {
4248 /* Line out and output */
4249 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4250 /* mono output */
4251 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4252 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4253 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4254 /* Mic2 (front panel) pin widget for input and vref at 80% */
4255 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4256 /* Line In pin widget for input */
4257 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4258 /* Headphone pin widget for output */
4259 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4260 /* CD pin widget for input */
4261 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4262 /* unmute amp left and right */
4263 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4264 /* set connection select to line in (default select for this ADC) */
4265 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4266 /* unmute Line-Out mixer amp left and right (volume = 0) */
4267 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4268 /* mute pin widget amp left and right (no gain on this amp) */
4269 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4270 /* unmute HP mixer amp left and right (volume = 0) */
4271 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4272 /* mute pin widget amp left and right (no gain on this amp) */
4273 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004274 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4275 * Line In 2 = 0x03
4276 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004277 /* mute analog inputs */
4278 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4279 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4280 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4281 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4282 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004283 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4284 /* Unmute Front out path */
4285 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4286 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4287 /* Unmute Headphone out path */
4288 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4289 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4290 /* Unmute Mono out path */
4291 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4292 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4293 { }
4294};
4295
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004296/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004297 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4298 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004299 */
4300static struct hda_verb alc260_fujitsu_init_verbs[] = {
4301 /* Disable all GPIOs */
4302 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4303 /* Internal speaker is connected to headphone pin */
4304 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4305 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4306 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004307 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4308 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4309 /* Ensure all other unused pins are disabled and muted. */
4310 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4311 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004312 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004313 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004314 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004315 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4316 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4317 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004318
Jonathan Woithef7ace402006-02-28 11:46:14 +01004319 /* Disable digital (SPDIF) pins */
4320 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4321 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004322
Jonathan Woithef7ace402006-02-28 11:46:14 +01004323 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4324 * when acting as an output.
4325 */
4326 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4327
4328 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004329 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4330 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4331 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4332 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4333 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4334 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4335 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4336 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4337 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004338
Jonathan Woithef7ace402006-02-28 11:46:14 +01004339 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4340 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4341 /* Unmute Line1 pin widget output buffer since it starts as an output.
4342 * If the pin mode is changed by the user the pin mode control will
4343 * take care of enabling the pin's input/output buffers as needed.
4344 * Therefore there's no need to enable the input buffer at this
4345 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004346 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004347 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004348 /* Unmute input buffer of pin widget used for Line-in (no equiv
4349 * mixer ctrl)
4350 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004351 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004352
Jonathan Woithef7ace402006-02-28 11:46:14 +01004353 /* Mute capture amp left and right */
4354 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4355 /* Set ADC connection select to match default mixer setting - line
4356 * in (on mic1 pin)
4357 */
4358 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004359
Jonathan Woithef7ace402006-02-28 11:46:14 +01004360 /* Do the same for the second ADC: mute capture input amp and
4361 * set ADC connection to line in (on mic1 pin)
4362 */
4363 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4364 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004365
Jonathan Woithef7ace402006-02-28 11:46:14 +01004366 /* Mute all inputs to mixer widget (even unconnected ones) */
4367 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4368 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4369 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4370 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4371 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4372 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4373 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4374 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004375
4376 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004377};
4378
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004379/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4380 * similar laptops (adapted from Fujitsu init verbs).
4381 */
4382static struct hda_verb alc260_acer_init_verbs[] = {
4383 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4384 * the headphone jack. Turn this on and rely on the standard mute
4385 * methods whenever the user wants to turn these outputs off.
4386 */
4387 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4388 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4389 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4390 /* Internal speaker/Headphone jack is connected to Line-out pin */
4391 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4392 /* Internal microphone/Mic jack is connected to Mic1 pin */
4393 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4394 /* Line In jack is connected to Line1 pin */
4395 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004396 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4397 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004398 /* Ensure all other unused pins are disabled and muted. */
4399 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4400 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004401 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4402 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4403 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4404 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4405 /* Disable digital (SPDIF) pins */
4406 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4407 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4408
4409 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4410 * bus when acting as outputs.
4411 */
4412 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4413 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4414
4415 /* Start with output sum widgets muted and their output gains at min */
4416 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4417 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4418 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4419 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4420 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4421 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4422 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4423 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4424 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4425
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004426 /* Unmute Line-out pin widget amp left and right
4427 * (no equiv mixer ctrl)
4428 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004429 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004430 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4431 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004432 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4433 * inputs. If the pin mode is changed by the user the pin mode control
4434 * will take care of enabling the pin's input/output buffers as needed.
4435 * Therefore there's no need to enable the input buffer at this
4436 * stage.
4437 */
4438 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4439 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4440
4441 /* Mute capture amp left and right */
4442 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4443 /* Set ADC connection select to match default mixer setting - mic
4444 * (on mic1 pin)
4445 */
4446 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4447
4448 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004449 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004450 */
4451 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004452 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004453
4454 /* Mute all inputs to mixer widget (even unconnected ones) */
4455 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4456 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4458 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4459 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4460 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4461 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4462 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4463
4464 { }
4465};
4466
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004467static struct hda_verb alc260_will_verbs[] = {
4468 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4469 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4470 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4471 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4472 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4473 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4474 {}
4475};
4476
4477static struct hda_verb alc260_replacer_672v_verbs[] = {
4478 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4479 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4480 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4481
4482 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4483 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4484 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4485
4486 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4487 {}
4488};
4489
4490/* toggle speaker-output according to the hp-jack state */
4491static void alc260_replacer_672v_automute(struct hda_codec *codec)
4492{
4493 unsigned int present;
4494
4495 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4496 present = snd_hda_codec_read(codec, 0x0f, 0,
4497 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4498 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004499 snd_hda_codec_write_cache(codec, 0x01, 0,
4500 AC_VERB_SET_GPIO_DATA, 1);
4501 snd_hda_codec_write_cache(codec, 0x0f, 0,
4502 AC_VERB_SET_PIN_WIDGET_CONTROL,
4503 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004504 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004505 snd_hda_codec_write_cache(codec, 0x01, 0,
4506 AC_VERB_SET_GPIO_DATA, 0);
4507 snd_hda_codec_write_cache(codec, 0x0f, 0,
4508 AC_VERB_SET_PIN_WIDGET_CONTROL,
4509 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004510 }
4511}
4512
4513static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4514 unsigned int res)
4515{
4516 if ((res >> 26) == ALC880_HP_EVENT)
4517 alc260_replacer_672v_automute(codec);
4518}
4519
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004520/* Test configuration for debugging, modelled after the ALC880 test
4521 * configuration.
4522 */
4523#ifdef CONFIG_SND_DEBUG
4524static hda_nid_t alc260_test_dac_nids[1] = {
4525 0x02,
4526};
4527static hda_nid_t alc260_test_adc_nids[2] = {
4528 0x04, 0x05,
4529};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004530/* For testing the ALC260, each input MUX needs its own definition since
4531 * the signal assignments are different. This assumes that the first ADC
4532 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004533 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004534static struct hda_input_mux alc260_test_capture_sources[2] = {
4535 {
4536 .num_items = 7,
4537 .items = {
4538 { "MIC1 pin", 0x0 },
4539 { "MIC2 pin", 0x1 },
4540 { "LINE1 pin", 0x2 },
4541 { "LINE2 pin", 0x3 },
4542 { "CD pin", 0x4 },
4543 { "LINE-OUT pin", 0x5 },
4544 { "HP-OUT pin", 0x6 },
4545 },
4546 },
4547 {
4548 .num_items = 8,
4549 .items = {
4550 { "MIC1 pin", 0x0 },
4551 { "MIC2 pin", 0x1 },
4552 { "LINE1 pin", 0x2 },
4553 { "LINE2 pin", 0x3 },
4554 { "CD pin", 0x4 },
4555 { "Mixer", 0x5 },
4556 { "LINE-OUT pin", 0x6 },
4557 { "HP-OUT pin", 0x7 },
4558 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004559 },
4560};
4561static struct snd_kcontrol_new alc260_test_mixer[] = {
4562 /* Output driver widgets */
4563 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4564 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4565 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4566 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4567 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4568 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4569
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004570 /* Modes for retasking pin widgets
4571 * Note: the ALC260 doesn't seem to act on requests to enable mic
4572 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4573 * mention this restriction. At this stage it's not clear whether
4574 * this behaviour is intentional or is a hardware bug in chip
4575 * revisions available at least up until early 2006. Therefore for
4576 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4577 * choices, but if it turns out that the lack of mic bias for these
4578 * NIDs is intentional we could change their modes from
4579 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4580 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004581 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4582 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4583 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4584 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4585 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4586 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4587
4588 /* Loopback mixer controls */
4589 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4590 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4591 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4592 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4593 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4594 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4595 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4596 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4597 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4598 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4599 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4600 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4601 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4602 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4603 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4604 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004605
4606 /* Controls for GPIO pins, assuming they are configured as outputs */
4607 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4608 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4609 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4610 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4611
Jonathan Woithe92621f12006-02-28 11:47:47 +01004612 /* Switches to allow the digital IO pins to be enabled. The datasheet
4613 * is ambigious as to which NID is which; testing on laptops which
4614 * make this output available should provide clarification.
4615 */
4616 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4617 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4618
Jonathan Woithef8225f62008-01-08 12:16:54 +01004619 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4620 * this output to turn on an external amplifier.
4621 */
4622 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4623 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4624
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004625 { } /* end */
4626};
4627static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004628 /* Enable all GPIOs as outputs with an initial value of 0 */
4629 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4630 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4631 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4632
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004633 /* Enable retasking pins as output, initially without power amp */
4634 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4635 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4636 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4637 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4638 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4639 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4640
Jonathan Woithe92621f12006-02-28 11:47:47 +01004641 /* Disable digital (SPDIF) pins initially, but users can enable
4642 * them via a mixer switch. In the case of SPDIF-out, this initverb
4643 * payload also sets the generation to 0, output to be in "consumer"
4644 * PCM format, copyright asserted, no pre-emphasis and no validity
4645 * control.
4646 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004647 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4648 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4649
Jonathan Woithef7ace402006-02-28 11:46:14 +01004650 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004651 * OUT1 sum bus when acting as an output.
4652 */
4653 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4654 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4655 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4656 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4657
4658 /* Start with output sum widgets muted and their output gains at min */
4659 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4660 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4661 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4662 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4663 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4664 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4665 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4666 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4667 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4668
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004669 /* Unmute retasking pin widget output buffers since the default
4670 * state appears to be output. As the pin mode is changed by the
4671 * user the pin mode control will take care of enabling the pin's
4672 * input/output buffers as needed.
4673 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004674 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4675 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4676 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4677 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4678 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4679 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4680 /* Also unmute the mono-out pin widget */
4681 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4682
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004683 /* Mute capture amp left and right */
4684 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004685 /* Set ADC connection select to match default mixer setting (mic1
4686 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004687 */
4688 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4689
4690 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004691 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004692 */
4693 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4694 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4695
4696 /* Mute all inputs to mixer widget (even unconnected ones) */
4697 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4698 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4699 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4700 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4701 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4702 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4703 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4704 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4705
4706 { }
4707};
4708#endif
4709
Takashi Iwai63300792008-01-24 15:31:36 +01004710#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4711#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004713#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4714#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4715
Kailang Yangdf694da2005-12-05 19:42:22 +01004716/*
4717 * for BIOS auto-configuration
4718 */
4719
4720static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4721 const char *pfx)
4722{
4723 hda_nid_t nid_vol;
4724 unsigned long vol_val, sw_val;
4725 char name[32];
4726 int err;
4727
4728 if (nid >= 0x0f && nid < 0x11) {
4729 nid_vol = nid - 0x7;
4730 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4731 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4732 } else if (nid == 0x11) {
4733 nid_vol = nid - 0x7;
4734 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4735 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4736 } else if (nid >= 0x12 && nid <= 0x15) {
4737 nid_vol = 0x08;
4738 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4739 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4740 } else
4741 return 0; /* N/A */
4742
4743 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004744 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4745 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004746 return err;
4747 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004748 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4749 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004750 return err;
4751 return 1;
4752}
4753
4754/* add playback controls from the parsed DAC table */
4755static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4756 const struct auto_pin_cfg *cfg)
4757{
4758 hda_nid_t nid;
4759 int err;
4760
4761 spec->multiout.num_dacs = 1;
4762 spec->multiout.dac_nids = spec->private_dac_nids;
4763 spec->multiout.dac_nids[0] = 0x02;
4764
4765 nid = cfg->line_out_pins[0];
4766 if (nid) {
4767 err = alc260_add_playback_controls(spec, nid, "Front");
4768 if (err < 0)
4769 return err;
4770 }
4771
Takashi Iwai82bc9552006-03-21 11:24:42 +01004772 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004773 if (nid) {
4774 err = alc260_add_playback_controls(spec, nid, "Speaker");
4775 if (err < 0)
4776 return err;
4777 }
4778
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004779 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004780 if (nid) {
4781 err = alc260_add_playback_controls(spec, nid, "Headphone");
4782 if (err < 0)
4783 return err;
4784 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004785 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004786}
4787
4788/* create playback/capture controls for input pins */
4789static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4790 const struct auto_pin_cfg *cfg)
4791{
Kailang Yangdf694da2005-12-05 19:42:22 +01004792 struct hda_input_mux *imux = &spec->private_imux;
4793 int i, err, idx;
4794
4795 for (i = 0; i < AUTO_PIN_LAST; i++) {
4796 if (cfg->input_pins[i] >= 0x12) {
4797 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004798 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004799 auto_pin_cfg_labels[i], idx,
4800 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004801 if (err < 0)
4802 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004803 imux->items[imux->num_items].label =
4804 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004805 imux->items[imux->num_items].index = idx;
4806 imux->num_items++;
4807 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004808 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004809 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004810 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004811 auto_pin_cfg_labels[i], idx,
4812 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004813 if (err < 0)
4814 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004815 imux->items[imux->num_items].label =
4816 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004817 imux->items[imux->num_items].index = idx;
4818 imux->num_items++;
4819 }
4820 }
4821 return 0;
4822}
4823
4824static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4825 hda_nid_t nid, int pin_type,
4826 int sel_idx)
4827{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004828 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01004829 /* need the manual connection? */
4830 if (nid >= 0x12) {
4831 int idx = nid - 0x12;
4832 snd_hda_codec_write(codec, idx + 0x0b, 0,
4833 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004834 }
4835}
4836
4837static void alc260_auto_init_multi_out(struct hda_codec *codec)
4838{
4839 struct alc_spec *spec = codec->spec;
4840 hda_nid_t nid;
4841
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004842 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004843 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004844 if (nid) {
4845 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4846 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4847 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004848
Takashi Iwai82bc9552006-03-21 11:24:42 +01004849 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004850 if (nid)
4851 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4852
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004853 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004854 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004855 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004856}
Kailang Yangdf694da2005-12-05 19:42:22 +01004857
4858#define ALC260_PIN_CD_NID 0x16
4859static void alc260_auto_init_analog_input(struct hda_codec *codec)
4860{
4861 struct alc_spec *spec = codec->spec;
4862 int i;
4863
4864 for (i = 0; i < AUTO_PIN_LAST; i++) {
4865 hda_nid_t nid = spec->autocfg.input_pins[i];
4866 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004867 snd_hda_codec_write(codec, nid, 0,
4868 AC_VERB_SET_PIN_WIDGET_CONTROL,
4869 i <= AUTO_PIN_FRONT_MIC ?
4870 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004871 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004872 snd_hda_codec_write(codec, nid, 0,
4873 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004874 AMP_OUT_MUTE);
4875 }
4876 }
4877}
4878
4879/*
4880 * generic initialization of ADC, input mixers and output mixers
4881 */
4882static struct hda_verb alc260_volume_init_verbs[] = {
4883 /*
4884 * Unmute ADC0-1 and set the default input to mic-in
4885 */
4886 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4887 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4888 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4889 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4890
4891 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4892 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004893 * Note: PASD motherboards uses the Line In 2 as the input for
4894 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004895 */
4896 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004897 /* mute analog inputs */
4898 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4899 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4900 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4901 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4902 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004903
4904 /*
4905 * Set up output mixers (0x08 - 0x0a)
4906 */
4907 /* set vol=0 to output mixers */
4908 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4909 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4910 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4911 /* set up input amps for analog loopback */
4912 /* Amp Indices: DAC = 0, mixer = 1 */
4913 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4914 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4915 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4916 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4917 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4918 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4919
4920 { }
4921};
4922
4923static int alc260_parse_auto_config(struct hda_codec *codec)
4924{
4925 struct alc_spec *spec = codec->spec;
4926 unsigned int wcap;
4927 int err;
4928 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
4929
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004930 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4931 alc260_ignore);
4932 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004933 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004934 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
4935 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01004936 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004937 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01004938 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004939 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
4940 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004941 return err;
4942
4943 spec->multiout.max_channels = 2;
4944
4945 if (spec->autocfg.dig_out_pin)
4946 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
4947 if (spec->kctl_alloc)
4948 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4949
4950 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
4951
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004952 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01004953 spec->input_mux = &spec->private_imux;
4954
4955 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004956 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01004957 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
Takashi Iwai67ebcb02008-02-19 15:03:57 +01004958 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004959 spec->adc_nids = alc260_adc_nids_alt;
4960 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
4961 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004962 } else {
4963 spec->adc_nids = alc260_adc_nids;
4964 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
4965 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004966 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004967 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01004968
4969 return 1;
4970}
4971
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004972/* additional initialization for auto-configuration model */
4973static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01004974{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004975 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004976 alc260_auto_init_multi_out(codec);
4977 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004978 if (spec->unsol_event)
4979 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01004980}
4981
Takashi Iwaicb53c622007-08-10 17:21:45 +02004982#ifdef CONFIG_SND_HDA_POWER_SAVE
4983static struct hda_amp_list alc260_loopbacks[] = {
4984 { 0x07, HDA_INPUT, 0 },
4985 { 0x07, HDA_INPUT, 1 },
4986 { 0x07, HDA_INPUT, 2 },
4987 { 0x07, HDA_INPUT, 3 },
4988 { 0x07, HDA_INPUT, 4 },
4989 { } /* end */
4990};
4991#endif
4992
Kailang Yangdf694da2005-12-05 19:42:22 +01004993/*
4994 * ALC260 configurations
4995 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004996static const char *alc260_models[ALC260_MODEL_LAST] = {
4997 [ALC260_BASIC] = "basic",
4998 [ALC260_HP] = "hp",
4999 [ALC260_HP_3013] = "hp-3013",
5000 [ALC260_FUJITSU_S702X] = "fujitsu",
5001 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005002 [ALC260_WILL] = "will",
5003 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005004#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005005 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005006#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005007 [ALC260_AUTO] = "auto",
5008};
5009
5010static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005011 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005012 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005013 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005014 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005015 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
5016 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
5017 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
5018 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5019 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5020 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5021 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5022 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5023 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5024 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5025 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5026 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005027 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005028 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005029 {}
5030};
5031
Kailang Yangdf694da2005-12-05 19:42:22 +01005032static struct alc_config_preset alc260_presets[] = {
5033 [ALC260_BASIC] = {
5034 .mixers = { alc260_base_output_mixer,
5035 alc260_input_mixer,
5036 alc260_pc_beep_mixer,
5037 alc260_capture_mixer },
5038 .init_verbs = { alc260_init_verbs },
5039 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5040 .dac_nids = alc260_dac_nids,
5041 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5042 .adc_nids = alc260_adc_nids,
5043 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5044 .channel_mode = alc260_modes,
5045 .input_mux = &alc260_capture_source,
5046 },
5047 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005048 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005049 alc260_input_mixer,
5050 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005051 .init_verbs = { alc260_init_verbs,
5052 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005053 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5054 .dac_nids = alc260_dac_nids,
5055 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5056 .adc_nids = alc260_hp_adc_nids,
5057 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5058 .channel_mode = alc260_modes,
5059 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005060 .unsol_event = alc260_hp_unsol_event,
5061 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005062 },
5063 [ALC260_HP_3013] = {
5064 .mixers = { alc260_hp_3013_mixer,
5065 alc260_input_mixer,
5066 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005067 .init_verbs = { alc260_hp_3013_init_verbs,
5068 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005069 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5070 .dac_nids = alc260_dac_nids,
5071 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5072 .adc_nids = alc260_hp_adc_nids,
5073 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5074 .channel_mode = alc260_modes,
5075 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005076 .unsol_event = alc260_hp_3013_unsol_event,
5077 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005078 },
5079 [ALC260_FUJITSU_S702X] = {
5080 .mixers = { alc260_fujitsu_mixer,
5081 alc260_capture_mixer },
5082 .init_verbs = { alc260_fujitsu_init_verbs },
5083 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5084 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005085 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5086 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005087 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5088 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005089 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5090 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005091 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005092 [ALC260_ACER] = {
5093 .mixers = { alc260_acer_mixer,
5094 alc260_capture_mixer },
5095 .init_verbs = { alc260_acer_init_verbs },
5096 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5097 .dac_nids = alc260_dac_nids,
5098 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5099 .adc_nids = alc260_dual_adc_nids,
5100 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5101 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005102 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5103 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005104 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005105 [ALC260_WILL] = {
5106 .mixers = { alc260_will_mixer,
5107 alc260_capture_mixer },
5108 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5109 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5110 .dac_nids = alc260_dac_nids,
5111 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5112 .adc_nids = alc260_adc_nids,
5113 .dig_out_nid = ALC260_DIGOUT_NID,
5114 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5115 .channel_mode = alc260_modes,
5116 .input_mux = &alc260_capture_source,
5117 },
5118 [ALC260_REPLACER_672V] = {
5119 .mixers = { alc260_replacer_672v_mixer,
5120 alc260_capture_mixer },
5121 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5122 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5123 .dac_nids = alc260_dac_nids,
5124 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5125 .adc_nids = alc260_adc_nids,
5126 .dig_out_nid = ALC260_DIGOUT_NID,
5127 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5128 .channel_mode = alc260_modes,
5129 .input_mux = &alc260_capture_source,
5130 .unsol_event = alc260_replacer_672v_unsol_event,
5131 .init_hook = alc260_replacer_672v_automute,
5132 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005133#ifdef CONFIG_SND_DEBUG
5134 [ALC260_TEST] = {
5135 .mixers = { alc260_test_mixer,
5136 alc260_capture_mixer },
5137 .init_verbs = { alc260_test_init_verbs },
5138 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5139 .dac_nids = alc260_test_dac_nids,
5140 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5141 .adc_nids = alc260_test_adc_nids,
5142 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5143 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005144 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5145 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005146 },
5147#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005148};
5149
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150static int patch_alc260(struct hda_codec *codec)
5151{
5152 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005153 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005155 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 if (spec == NULL)
5157 return -ENOMEM;
5158
5159 codec->spec = spec;
5160
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005161 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5162 alc260_models,
5163 alc260_cfg_tbl);
5164 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005165 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5166 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005167 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005168 }
5169
Kailang Yangdf694da2005-12-05 19:42:22 +01005170 if (board_config == ALC260_AUTO) {
5171 /* automatic parse from the BIOS config */
5172 err = alc260_parse_auto_config(codec);
5173 if (err < 0) {
5174 alc_free(codec);
5175 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005176 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005177 printk(KERN_INFO
5178 "hda_codec: Cannot set up configuration "
5179 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005180 board_config = ALC260_BASIC;
5181 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183
Kailang Yangdf694da2005-12-05 19:42:22 +01005184 if (board_config != ALC260_AUTO)
5185 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186
5187 spec->stream_name_analog = "ALC260 Analog";
5188 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5189 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5190
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005191 spec->stream_name_digital = "ALC260 Digital";
5192 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5193 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5194
Takashi Iwai2134ea42008-01-10 16:53:55 +01005195 spec->vmaster_nid = 0x08;
5196
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005198 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005199 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005200#ifdef CONFIG_SND_HDA_POWER_SAVE
5201 if (!spec->loopback.amplist)
5202 spec->loopback.amplist = alc260_loopbacks;
5203#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204
5205 return 0;
5206}
5207
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005208
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209/*
5210 * ALC882 support
5211 *
5212 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5213 * configuration. Each pin widget can choose any input DACs and a mixer.
5214 * Each ADC is connected from a mixer of all inputs. This makes possible
5215 * 6-channel independent captures.
5216 *
5217 * In addition, an independent DAC for the multi-playback (not used in this
5218 * driver yet).
5219 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005220#define ALC882_DIGOUT_NID 0x06
5221#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005223static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 { 8, NULL }
5225};
5226
5227static hda_nid_t alc882_dac_nids[4] = {
5228 /* front, rear, clfe, rear_surr */
5229 0x02, 0x03, 0x04, 0x05
5230};
5231
Kailang Yangdf694da2005-12-05 19:42:22 +01005232/* identical with ALC880 */
5233#define alc882_adc_nids alc880_adc_nids
5234#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235
Takashi Iwaie1406342008-02-11 18:32:32 +01005236static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5237static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5238
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239/* input MUX */
5240/* FIXME: should be a matrix-type input source selection */
5241
5242static struct hda_input_mux alc882_capture_source = {
5243 .num_items = 4,
5244 .items = {
5245 { "Mic", 0x0 },
5246 { "Front Mic", 0x1 },
5247 { "Line", 0x2 },
5248 { "CD", 0x4 },
5249 },
5250};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251#define alc882_mux_enum_info alc_mux_enum_info
5252#define alc882_mux_enum_get alc_mux_enum_get
5253
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005254static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5255 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256{
5257 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5258 struct alc_spec *spec = codec->spec;
5259 const struct hda_input_mux *imux = spec->input_mux;
5260 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai88c71a92008-02-14 17:27:17 +01005261 hda_nid_t nid = spec->capsrc_nids ?
5262 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5264 unsigned int i, idx;
5265
5266 idx = ucontrol->value.enumerated.item[0];
5267 if (idx >= imux->num_items)
5268 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005269 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 return 0;
5271 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005272 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5273 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005274 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005275 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 }
5277 *cur_val = idx;
5278 return 1;
5279}
5280
Kailang Yangdf694da2005-12-05 19:42:22 +01005281/*
Kailang Yang272a5272007-05-14 11:00:38 +02005282 * 2ch mode
5283 */
5284static struct hda_verb alc882_3ST_ch2_init[] = {
5285 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5286 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5287 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5288 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5289 { } /* end */
5290};
5291
5292/*
5293 * 6ch mode
5294 */
5295static struct hda_verb alc882_3ST_ch6_init[] = {
5296 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5297 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5298 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5299 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5300 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5301 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5302 { } /* end */
5303};
5304
5305static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5306 { 2, alc882_3ST_ch2_init },
5307 { 6, alc882_3ST_ch6_init },
5308};
5309
5310/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005311 * 6ch mode
5312 */
5313static struct hda_verb alc882_sixstack_ch6_init[] = {
5314 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5315 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5316 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5317 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5318 { } /* end */
5319};
5320
5321/*
5322 * 8ch mode
5323 */
5324static struct hda_verb alc882_sixstack_ch8_init[] = {
5325 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5326 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5327 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5328 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5329 { } /* end */
5330};
5331
5332static struct hda_channel_mode alc882_sixstack_modes[2] = {
5333 { 6, alc882_sixstack_ch6_init },
5334 { 8, alc882_sixstack_ch8_init },
5335};
5336
Takashi Iwai87350ad2007-08-16 18:19:38 +02005337/*
5338 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5339 */
5340
5341/*
5342 * 2ch mode
5343 */
5344static struct hda_verb alc885_mbp_ch2_init[] = {
5345 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5346 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5347 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5348 { } /* end */
5349};
5350
5351/*
5352 * 6ch mode
5353 */
5354static struct hda_verb alc885_mbp_ch6_init[] = {
5355 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5356 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5357 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5358 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5359 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5360 { } /* end */
5361};
5362
5363static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5364 { 2, alc885_mbp_ch2_init },
5365 { 6, alc885_mbp_ch6_init },
5366};
5367
5368
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5370 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5371 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005372static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005373 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005374 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005375 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005376 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005377 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5378 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005379 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5380 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005381 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005382 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5384 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5385 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5386 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5387 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5388 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005389 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5391 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005392 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5394 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5395 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 { } /* end */
5397};
5398
Takashi Iwai87350ad2007-08-16 18:19:38 +02005399static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005400 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5401 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5402 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5403 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5404 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5405 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005406 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5407 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005408 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005409 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5410 { } /* end */
5411};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005412static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5413 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5414 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5415 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5416 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5417 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5418 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5419 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5420 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5421 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5422 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5423 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5424 { } /* end */
5425};
5426
Kailang Yang272a5272007-05-14 11:00:38 +02005427static struct snd_kcontrol_new alc882_targa_mixer[] = {
5428 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5429 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5430 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5431 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5432 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5433 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5434 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5435 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5436 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005437 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005438 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5439 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005440 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005441 { } /* end */
5442};
5443
5444/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5445 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5446 */
5447static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5448 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5449 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5450 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5451 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5452 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5453 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5454 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5455 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5456 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5457 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5459 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005460 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005461 { } /* end */
5462};
5463
Takashi Iwai914759b2007-09-06 14:52:04 +02005464static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5465 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5466 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5467 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5468 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5469 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5470 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5471 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5472 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5473 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5474 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5475 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5476 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5477 { } /* end */
5478};
5479
Kailang Yangdf694da2005-12-05 19:42:22 +01005480static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5481 {
5482 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5483 .name = "Channel Mode",
5484 .info = alc_ch_mode_info,
5485 .get = alc_ch_mode_get,
5486 .put = alc_ch_mode_put,
5487 },
5488 { } /* end */
5489};
5490
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491static struct hda_verb alc882_init_verbs[] = {
5492 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005493 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5494 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5495 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005497 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5498 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5499 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005501 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5502 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5503 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005505 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5506 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5507 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005509 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005510 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005511 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005513 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005514 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005515 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005517 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005518 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005519 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005521 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005522 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005523 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005525 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005526 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005527 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5528 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005529 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005530 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5531 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005532 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005533 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5534 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5535 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5536 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5537 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005539 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
5541 /* FIXME: use matrix-type input source selection */
5542 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5543 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005544 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5545 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5546 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5547 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005549 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5550 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5551 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5552 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005554 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5555 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5556 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5557 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5558 /* ADC1: mute amp left and right */
5559 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005560 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005561 /* ADC2: mute amp left and right */
5562 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005563 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005564 /* ADC3: mute amp left and right */
5565 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005566 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
5568 { }
5569};
5570
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005571static struct hda_verb alc882_eapd_verbs[] = {
5572 /* change to EAPD mode */
5573 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005574 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005575 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005576};
5577
Tobin Davis9102cd12006-12-15 10:02:12 +01005578/* Mac Pro test */
5579static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5580 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5581 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5582 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5583 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5584 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5585 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5586 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5587 { } /* end */
5588};
5589
5590static struct hda_verb alc882_macpro_init_verbs[] = {
5591 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5592 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5593 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5594 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5595 /* Front Pin: output 0 (0x0c) */
5596 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5597 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5598 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5599 /* Front Mic pin: input vref at 80% */
5600 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5601 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5602 /* Speaker: output */
5603 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5604 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5605 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5606 /* Headphone output (output 0 - 0x0c) */
5607 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5608 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5609 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5610
5611 /* FIXME: use matrix-type input source selection */
5612 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5613 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5614 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5615 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5616 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5617 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5618 /* Input mixer2 */
5619 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5620 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5621 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5622 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5623 /* Input mixer3 */
5624 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5625 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5626 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5627 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5628 /* ADC1: mute amp left and right */
5629 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5630 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5631 /* ADC2: mute amp left and right */
5632 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5633 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5634 /* ADC3: mute amp left and right */
5635 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5636 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5637
5638 { }
5639};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005640
Takashi Iwai87350ad2007-08-16 18:19:38 +02005641/* Macbook Pro rev3 */
5642static struct hda_verb alc885_mbp3_init_verbs[] = {
5643 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5644 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5645 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5646 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5647 /* Rear mixer */
5648 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5649 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5650 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5651 /* Front Pin: output 0 (0x0c) */
5652 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5653 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5654 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5655 /* HP Pin: output 0 (0x0d) */
5656 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5657 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5658 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5659 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5660 /* Mic (rear) pin: input vref at 80% */
5661 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5662 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5663 /* Front Mic pin: input vref at 80% */
5664 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5665 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5666 /* Line In pin: use output 1 when in LineOut mode */
5667 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5668 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5669 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5670
5671 /* FIXME: use matrix-type input source selection */
5672 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5673 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5674 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5675 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5676 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5677 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5678 /* Input mixer2 */
5679 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5680 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5681 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5682 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5683 /* Input mixer3 */
5684 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5685 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5686 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5687 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5688 /* ADC1: mute amp left and right */
5689 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5690 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5691 /* ADC2: mute amp left and right */
5692 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5693 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5694 /* ADC3: mute amp left and right */
5695 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5696 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5697
5698 { }
5699};
5700
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005701/* iMac 24 mixer. */
5702static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5703 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5704 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5705 { } /* end */
5706};
5707
5708/* iMac 24 init verbs. */
5709static struct hda_verb alc885_imac24_init_verbs[] = {
5710 /* Internal speakers: output 0 (0x0c) */
5711 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5712 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5713 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5714 /* Internal speakers: output 0 (0x0c) */
5715 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5716 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5717 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5718 /* Headphone: output 0 (0x0c) */
5719 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5720 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5721 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5722 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5723 /* Front Mic: input vref at 80% */
5724 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5725 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5726 { }
5727};
5728
5729/* Toggle speaker-output according to the hp-jack state */
5730static void alc885_imac24_automute(struct hda_codec *codec)
5731{
5732 unsigned int present;
5733
5734 present = snd_hda_codec_read(codec, 0x14, 0,
5735 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005736 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5737 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5738 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5739 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005740}
5741
5742/* Processes unsolicited events. */
5743static void alc885_imac24_unsol_event(struct hda_codec *codec,
5744 unsigned int res)
5745{
5746 /* Headphone insertion or removal. */
5747 if ((res >> 26) == ALC880_HP_EVENT)
5748 alc885_imac24_automute(codec);
5749}
5750
Takashi Iwai87350ad2007-08-16 18:19:38 +02005751static void alc885_mbp3_automute(struct hda_codec *codec)
5752{
5753 unsigned int present;
5754
5755 present = snd_hda_codec_read(codec, 0x15, 0,
5756 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5757 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5758 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5759 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5760 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5761
5762}
5763static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5764 unsigned int res)
5765{
5766 /* Headphone insertion or removal. */
5767 if ((res >> 26) == ALC880_HP_EVENT)
5768 alc885_mbp3_automute(codec);
5769}
5770
5771
Kailang Yang272a5272007-05-14 11:00:38 +02005772static struct hda_verb alc882_targa_verbs[] = {
5773 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5774 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5775
5776 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5777 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5778
5779 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5780 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5781 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5782
5783 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5784 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5785 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5786 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5787 { } /* end */
5788};
5789
5790/* toggle speaker-output according to the hp-jack state */
5791static void alc882_targa_automute(struct hda_codec *codec)
5792{
5793 unsigned int present;
5794
5795 present = snd_hda_codec_read(codec, 0x14, 0,
5796 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005797 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5798 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005799 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5800 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005801}
5802
5803static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5804{
5805 /* Looks like the unsol event is incompatible with the standard
5806 * definition. 4bit tag is placed at 26 bit!
5807 */
5808 if (((res >> 26) == ALC880_HP_EVENT)) {
5809 alc882_targa_automute(codec);
5810 }
5811}
5812
5813static struct hda_verb alc882_asus_a7j_verbs[] = {
5814 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5815 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5816
5817 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5818 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5819 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5820
5821 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5822 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5823 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5824
5825 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5826 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5827 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5828 { } /* end */
5829};
5830
Takashi Iwai914759b2007-09-06 14:52:04 +02005831static struct hda_verb alc882_asus_a7m_verbs[] = {
5832 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5833 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5834
5835 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5836 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5837 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5838
5839 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5840 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5841 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5842
5843 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5844 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5845 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5846 { } /* end */
5847};
5848
Tobin Davis9102cd12006-12-15 10:02:12 +01005849static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5850{
5851 unsigned int gpiostate, gpiomask, gpiodir;
5852
5853 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5854 AC_VERB_GET_GPIO_DATA, 0);
5855
5856 if (!muted)
5857 gpiostate |= (1 << pin);
5858 else
5859 gpiostate &= ~(1 << pin);
5860
5861 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5862 AC_VERB_GET_GPIO_MASK, 0);
5863 gpiomask |= (1 << pin);
5864
5865 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5866 AC_VERB_GET_GPIO_DIRECTION, 0);
5867 gpiodir |= (1 << pin);
5868
5869
5870 snd_hda_codec_write(codec, codec->afg, 0,
5871 AC_VERB_SET_GPIO_MASK, gpiomask);
5872 snd_hda_codec_write(codec, codec->afg, 0,
5873 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5874
5875 msleep(1);
5876
5877 snd_hda_codec_write(codec, codec->afg, 0,
5878 AC_VERB_SET_GPIO_DATA, gpiostate);
5879}
5880
Takashi Iwai7debbe52007-08-16 15:01:03 +02005881/* set up GPIO at initialization */
5882static void alc885_macpro_init_hook(struct hda_codec *codec)
5883{
5884 alc882_gpio_mute(codec, 0, 0);
5885 alc882_gpio_mute(codec, 1, 0);
5886}
5887
5888/* set up GPIO and update auto-muting at initialization */
5889static void alc885_imac24_init_hook(struct hda_codec *codec)
5890{
5891 alc885_macpro_init_hook(codec);
5892 alc885_imac24_automute(codec);
5893}
5894
Kailang Yangdf694da2005-12-05 19:42:22 +01005895/*
5896 * generic initialization of ADC, input mixers and output mixers
5897 */
5898static struct hda_verb alc882_auto_init_verbs[] = {
5899 /*
5900 * Unmute ADC0-2 and set the default input to mic-in
5901 */
5902 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5903 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5904 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5905 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5906 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5907 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5908
Takashi Iwaicb53c622007-08-10 17:21:45 +02005909 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01005910 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005911 * Note: PASD motherboards uses the Line In 2 as the input for
5912 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005913 */
5914 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005915 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5916 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5917 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5918 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5919 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005920
5921 /*
5922 * Set up output mixers (0x0c - 0x0f)
5923 */
5924 /* set vol=0 to output mixers */
5925 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5926 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5927 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5928 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5929 /* set up input amps for analog loopback */
5930 /* Amp Indices: DAC = 0, mixer = 1 */
5931 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5933 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5934 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5935 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5936 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5937 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5938 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5939 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5940 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5941
5942 /* FIXME: use matrix-type input source selection */
5943 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5944 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5945 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5946 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5947 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5948 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5949 /* Input mixer2 */
5950 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5951 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5952 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5953 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5954 /* Input mixer3 */
5955 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5956 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5957 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5958 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5959
5960 { }
5961};
5962
5963/* capture mixer elements */
5964static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
5965 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5966 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5967 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5968 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5969 {
5970 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5971 /* The multiple "Capture Source" controls confuse alsamixer
5972 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005973 */
5974 /* .name = "Capture Source", */
5975 .name = "Input Source",
5976 .count = 2,
5977 .info = alc882_mux_enum_info,
5978 .get = alc882_mux_enum_get,
5979 .put = alc882_mux_enum_put,
5980 },
5981 { } /* end */
5982};
5983
5984static struct snd_kcontrol_new alc882_capture_mixer[] = {
5985 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
5986 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
5987 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
5988 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
5989 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
5990 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
5991 {
5992 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5993 /* The multiple "Capture Source" controls confuse alsamixer
5994 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005995 */
5996 /* .name = "Capture Source", */
5997 .name = "Input Source",
5998 .count = 3,
5999 .info = alc882_mux_enum_info,
6000 .get = alc882_mux_enum_get,
6001 .put = alc882_mux_enum_put,
6002 },
6003 { } /* end */
6004};
6005
Takashi Iwaicb53c622007-08-10 17:21:45 +02006006#ifdef CONFIG_SND_HDA_POWER_SAVE
6007#define alc882_loopbacks alc880_loopbacks
6008#endif
6009
Kailang Yangdf694da2005-12-05 19:42:22 +01006010/* pcm configuration: identiacal with ALC880 */
6011#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6012#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6013#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6014#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6015
6016/*
6017 * configuration and preset
6018 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006019static const char *alc882_models[ALC882_MODEL_LAST] = {
6020 [ALC882_3ST_DIG] = "3stack-dig",
6021 [ALC882_6ST_DIG] = "6stack-dig",
6022 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006023 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006024 [ALC882_TARGA] = "targa",
6025 [ALC882_ASUS_A7J] = "asus-a7j",
6026 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006027 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006028 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006029 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006030 [ALC882_AUTO] = "auto",
6031};
6032
6033static struct snd_pci_quirk alc882_cfg_tbl[] = {
6034 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006035 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006036 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006037 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006038 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006039 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006040 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006041 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006042 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006043 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6044 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6045 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006046 {}
6047};
6048
6049static struct alc_config_preset alc882_presets[] = {
6050 [ALC882_3ST_DIG] = {
6051 .mixers = { alc882_base_mixer },
6052 .init_verbs = { alc882_init_verbs },
6053 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6054 .dac_nids = alc882_dac_nids,
6055 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006056 .dig_in_nid = ALC882_DIGIN_NID,
6057 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6058 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006059 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006060 .input_mux = &alc882_capture_source,
6061 },
6062 [ALC882_6ST_DIG] = {
6063 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6064 .init_verbs = { alc882_init_verbs },
6065 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6066 .dac_nids = alc882_dac_nids,
6067 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006068 .dig_in_nid = ALC882_DIGIN_NID,
6069 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6070 .channel_mode = alc882_sixstack_modes,
6071 .input_mux = &alc882_capture_source,
6072 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006073 [ALC882_ARIMA] = {
6074 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6075 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6076 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6077 .dac_nids = alc882_dac_nids,
6078 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6079 .channel_mode = alc882_sixstack_modes,
6080 .input_mux = &alc882_capture_source,
6081 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006082 [ALC882_W2JC] = {
6083 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6084 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6085 alc880_gpio1_init_verbs },
6086 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6087 .dac_nids = alc882_dac_nids,
6088 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6089 .channel_mode = alc880_threestack_modes,
6090 .need_dac_fix = 1,
6091 .input_mux = &alc882_capture_source,
6092 .dig_out_nid = ALC882_DIGOUT_NID,
6093 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006094 [ALC885_MBP3] = {
6095 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6096 .init_verbs = { alc885_mbp3_init_verbs,
6097 alc880_gpio1_init_verbs },
6098 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6099 .dac_nids = alc882_dac_nids,
6100 .channel_mode = alc885_mbp_6ch_modes,
6101 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6102 .input_mux = &alc882_capture_source,
6103 .dig_out_nid = ALC882_DIGOUT_NID,
6104 .dig_in_nid = ALC882_DIGIN_NID,
6105 .unsol_event = alc885_mbp3_unsol_event,
6106 .init_hook = alc885_mbp3_automute,
6107 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006108 [ALC885_MACPRO] = {
6109 .mixers = { alc882_macpro_mixer },
6110 .init_verbs = { alc882_macpro_init_verbs },
6111 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6112 .dac_nids = alc882_dac_nids,
6113 .dig_out_nid = ALC882_DIGOUT_NID,
6114 .dig_in_nid = ALC882_DIGIN_NID,
6115 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6116 .channel_mode = alc882_ch_modes,
6117 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006118 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006119 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006120 [ALC885_IMAC24] = {
6121 .mixers = { alc885_imac24_mixer },
6122 .init_verbs = { alc885_imac24_init_verbs },
6123 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6124 .dac_nids = alc882_dac_nids,
6125 .dig_out_nid = ALC882_DIGOUT_NID,
6126 .dig_in_nid = ALC882_DIGIN_NID,
6127 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6128 .channel_mode = alc882_ch_modes,
6129 .input_mux = &alc882_capture_source,
6130 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006131 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006132 },
Kailang Yang272a5272007-05-14 11:00:38 +02006133 [ALC882_TARGA] = {
6134 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6135 alc882_capture_mixer },
6136 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6137 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6138 .dac_nids = alc882_dac_nids,
6139 .dig_out_nid = ALC882_DIGOUT_NID,
6140 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6141 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006142 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006143 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6144 .channel_mode = alc882_3ST_6ch_modes,
6145 .need_dac_fix = 1,
6146 .input_mux = &alc882_capture_source,
6147 .unsol_event = alc882_targa_unsol_event,
6148 .init_hook = alc882_targa_automute,
6149 },
6150 [ALC882_ASUS_A7J] = {
6151 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6152 alc882_capture_mixer },
6153 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6154 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6155 .dac_nids = alc882_dac_nids,
6156 .dig_out_nid = ALC882_DIGOUT_NID,
6157 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6158 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006159 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006160 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6161 .channel_mode = alc882_3ST_6ch_modes,
6162 .need_dac_fix = 1,
6163 .input_mux = &alc882_capture_source,
6164 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006165 [ALC882_ASUS_A7M] = {
6166 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6167 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6168 alc880_gpio1_init_verbs,
6169 alc882_asus_a7m_verbs },
6170 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6171 .dac_nids = alc882_dac_nids,
6172 .dig_out_nid = ALC882_DIGOUT_NID,
6173 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6174 .channel_mode = alc880_threestack_modes,
6175 .need_dac_fix = 1,
6176 .input_mux = &alc882_capture_source,
6177 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006178};
6179
6180
6181/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006182 * Pin config fixes
6183 */
6184enum {
6185 PINFIX_ABIT_AW9D_MAX
6186};
6187
6188static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6189 { 0x15, 0x01080104 }, /* side */
6190 { 0x16, 0x01011012 }, /* rear */
6191 { 0x17, 0x01016011 }, /* clfe */
6192 { }
6193};
6194
6195static const struct alc_pincfg *alc882_pin_fixes[] = {
6196 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6197};
6198
6199static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6200 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6201 {}
6202};
6203
6204/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006205 * BIOS auto configuration
6206 */
6207static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6208 hda_nid_t nid, int pin_type,
6209 int dac_idx)
6210{
6211 /* set as output */
6212 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006213 int idx;
6214
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006215 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006216 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6217 idx = 4;
6218 else
6219 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006220 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6221
6222}
6223
6224static void alc882_auto_init_multi_out(struct hda_codec *codec)
6225{
6226 struct alc_spec *spec = codec->spec;
6227 int i;
6228
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006229 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006230 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006231 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006232 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006233 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006234 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006235 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006236 }
6237}
6238
6239static void alc882_auto_init_hp_out(struct hda_codec *codec)
6240{
6241 struct alc_spec *spec = codec->spec;
6242 hda_nid_t pin;
6243
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006244 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006245 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006246 /* use dac 0 */
6247 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006248 pin = spec->autocfg.speaker_pins[0];
6249 if (pin)
6250 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006251}
6252
6253#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6254#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6255
6256static void alc882_auto_init_analog_input(struct hda_codec *codec)
6257{
6258 struct alc_spec *spec = codec->spec;
6259 int i;
6260
6261 for (i = 0; i < AUTO_PIN_LAST; i++) {
6262 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006263 unsigned int vref;
6264 if (!nid)
6265 continue;
6266 vref = PIN_IN;
6267 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
6268 if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) &
6269 AC_PINCAP_VREF_80)
6270 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006271 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006272 snd_hda_codec_write(codec, nid, 0,
6273 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6274 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6275 snd_hda_codec_write(codec, nid, 0,
6276 AC_VERB_SET_AMP_GAIN_MUTE,
6277 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006278 }
6279}
6280
Takashi Iwai776e1842007-08-29 15:07:11 +02006281/* add mic boosts if needed */
6282static int alc_auto_add_mic_boost(struct hda_codec *codec)
6283{
6284 struct alc_spec *spec = codec->spec;
6285 int err;
6286 hda_nid_t nid;
6287
6288 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006289 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006290 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6291 "Mic Boost",
6292 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6293 if (err < 0)
6294 return err;
6295 }
6296 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006297 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006298 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6299 "Front Mic Boost",
6300 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6301 if (err < 0)
6302 return err;
6303 }
6304 return 0;
6305}
6306
Kailang Yangdf694da2005-12-05 19:42:22 +01006307/* almost identical with ALC880 parser... */
6308static int alc882_parse_auto_config(struct hda_codec *codec)
6309{
6310 struct alc_spec *spec = codec->spec;
6311 int err = alc880_parse_auto_config(codec);
6312
6313 if (err < 0)
6314 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006315 else if (!err)
6316 return 0; /* no config found */
6317
6318 err = alc_auto_add_mic_boost(codec);
6319 if (err < 0)
6320 return err;
6321
6322 /* hack - override the init verbs */
6323 spec->init_verbs[0] = alc882_auto_init_verbs;
6324
6325 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006326}
6327
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006328/* additional initialization for auto-configuration model */
6329static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006330{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006331 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006332 alc882_auto_init_multi_out(codec);
6333 alc882_auto_init_hp_out(codec);
6334 alc882_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006335 if (spec->unsol_event)
6336 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006337}
6338
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339static int patch_alc882(struct hda_codec *codec)
6340{
6341 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006342 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006344 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 if (spec == NULL)
6346 return -ENOMEM;
6347
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 codec->spec = spec;
6349
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006350 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6351 alc882_models,
6352 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353
Kailang Yangdf694da2005-12-05 19:42:22 +01006354 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006355 /* Pick up systems that don't supply PCI SSID */
6356 switch (codec->subsystem_id) {
6357 case 0x106b0c00: /* Mac Pro */
6358 board_config = ALC885_MACPRO;
6359 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006360 case 0x106b1000: /* iMac 24 */
6361 board_config = ALC885_IMAC24;
6362 break;
Jiang zhe3d5fa2e2008-01-10 13:05:47 +01006363 case 0x106b00a1: /* Macbook */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006364 case 0x106b2c00: /* Macbook Pro rev3 */
6365 board_config = ALC885_MBP3;
6366 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006367 default:
6368 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6369 "trying auto-probe from BIOS...\n");
6370 board_config = ALC882_AUTO;
6371 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006372 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006373
Takashi Iwaif95474e2007-07-10 00:47:43 +02006374 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6375
Kailang Yangdf694da2005-12-05 19:42:22 +01006376 if (board_config == ALC882_AUTO) {
6377 /* automatic parse from the BIOS config */
6378 err = alc882_parse_auto_config(codec);
6379 if (err < 0) {
6380 alc_free(codec);
6381 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006382 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006383 printk(KERN_INFO
6384 "hda_codec: Cannot set up configuration "
6385 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006386 board_config = ALC882_3ST_DIG;
6387 }
6388 }
6389
6390 if (board_config != ALC882_AUTO)
6391 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392
6393 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006394 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6395 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006396 /* FIXME: setup DAC5 */
6397 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6398 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
6400 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006401 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6402 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006404 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006405 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006406 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006407 /* get type */
6408 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006409 if (wcap != AC_WID_AUD_IN) {
6410 spec->adc_nids = alc882_adc_nids_alt;
6411 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006412 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006413 spec->mixers[spec->num_mixers] =
6414 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006415 spec->num_mixers++;
6416 } else {
6417 spec->adc_nids = alc882_adc_nids;
6418 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006419 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006420 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6421 spec->num_mixers++;
6422 }
6423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424
Takashi Iwai2134ea42008-01-10 16:53:55 +01006425 spec->vmaster_nid = 0x0c;
6426
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006428 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006429 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006430#ifdef CONFIG_SND_HDA_POWER_SAVE
6431 if (!spec->loopback.amplist)
6432 spec->loopback.amplist = alc882_loopbacks;
6433#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434
6435 return 0;
6436}
6437
6438/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006439 * ALC883 support
6440 *
6441 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6442 * configuration. Each pin widget can choose any input DACs and a mixer.
6443 * Each ADC is connected from a mixer of all inputs. This makes possible
6444 * 6-channel independent captures.
6445 *
6446 * In addition, an independent DAC for the multi-playback (not used in this
6447 * driver yet).
6448 */
6449#define ALC883_DIGOUT_NID 0x06
6450#define ALC883_DIGIN_NID 0x0a
6451
6452static hda_nid_t alc883_dac_nids[4] = {
6453 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006454 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006455};
6456
6457static hda_nid_t alc883_adc_nids[2] = {
6458 /* ADC1-2 */
6459 0x08, 0x09,
6460};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006461
Takashi Iwaie1406342008-02-11 18:32:32 +01006462static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6463
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006464/* input MUX */
6465/* FIXME: should be a matrix-type input source selection */
6466
6467static struct hda_input_mux alc883_capture_source = {
6468 .num_items = 4,
6469 .items = {
6470 { "Mic", 0x0 },
6471 { "Front Mic", 0x1 },
6472 { "Line", 0x2 },
6473 { "CD", 0x4 },
6474 },
6475};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006476
6477static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6478 .num_items = 2,
6479 .items = {
6480 { "Mic", 0x1 },
6481 { "Line", 0x2 },
6482 },
6483};
6484
Kailang Yang272a5272007-05-14 11:00:38 +02006485static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6486 .num_items = 4,
6487 .items = {
6488 { "Mic", 0x0 },
6489 { "iMic", 0x1 },
6490 { "Line", 0x2 },
6491 { "CD", 0x4 },
6492 },
6493};
6494
Jiang zhefb97dc62008-03-06 11:07:11 +01006495static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6496 .num_items = 2,
6497 .items = {
6498 { "Mic", 0x0 },
6499 { "Int Mic", 0x1 },
6500 },
6501};
6502
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006503#define alc883_mux_enum_info alc_mux_enum_info
6504#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006505/* ALC883 has the ALC882-type input selection */
6506#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006507
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006508/*
6509 * 2ch mode
6510 */
6511static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6512 { 2, NULL }
6513};
6514
6515/*
6516 * 2ch mode
6517 */
6518static struct hda_verb alc883_3ST_ch2_init[] = {
6519 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6520 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6521 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6522 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6523 { } /* end */
6524};
6525
6526/*
Tobin Davisb2011312007-09-17 12:45:11 +02006527 * 4ch mode
6528 */
6529static struct hda_verb alc883_3ST_ch4_init[] = {
6530 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6531 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6532 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6533 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6534 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6535 { } /* end */
6536};
6537
6538/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006539 * 6ch mode
6540 */
6541static struct hda_verb alc883_3ST_ch6_init[] = {
6542 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6543 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6544 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6545 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6546 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6547 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6548 { } /* end */
6549};
6550
Tobin Davisb2011312007-09-17 12:45:11 +02006551static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006552 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006553 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006554 { 6, alc883_3ST_ch6_init },
6555};
6556
6557/*
6558 * 6ch mode
6559 */
6560static struct hda_verb alc883_sixstack_ch6_init[] = {
6561 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6562 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6563 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6564 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6565 { } /* end */
6566};
6567
6568/*
6569 * 8ch mode
6570 */
6571static struct hda_verb alc883_sixstack_ch8_init[] = {
6572 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6573 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6574 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6575 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6576 { } /* end */
6577};
6578
6579static struct hda_channel_mode alc883_sixstack_modes[2] = {
6580 { 6, alc883_sixstack_ch6_init },
6581 { 8, alc883_sixstack_ch8_init },
6582};
6583
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006584static struct hda_verb alc883_medion_eapd_verbs[] = {
6585 /* eanable EAPD on medion laptop */
6586 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6587 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6588 { }
6589};
6590
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006591/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6592 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6593 */
6594
6595static struct snd_kcontrol_new alc883_base_mixer[] = {
6596 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6597 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6598 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6599 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6600 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6601 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6602 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6603 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6604 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6605 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6606 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6607 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6608 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6609 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6610 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6611 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006612 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006613 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6614 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006615 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006616 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6617 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6618 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6619 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6620 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6621 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6622 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6623 {
6624 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6625 /* .name = "Capture Source", */
6626 .name = "Input Source",
6627 .count = 2,
6628 .info = alc883_mux_enum_info,
6629 .get = alc883_mux_enum_get,
6630 .put = alc883_mux_enum_put,
6631 },
6632 { } /* end */
6633};
6634
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006635static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6636 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6637 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6638 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6639 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6640 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6641 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6642 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6643 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6644 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6645 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6646 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6647 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6648 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6649 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6650 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6651 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6652 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6653 {
6654 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6655 /* .name = "Capture Source", */
6656 .name = "Input Source",
6657 .count = 2,
6658 .info = alc883_mux_enum_info,
6659 .get = alc883_mux_enum_get,
6660 .put = alc883_mux_enum_put,
6661 },
6662 { } /* end */
6663};
6664
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01006665static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01006666 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6667 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
6668 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6669 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
6670 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6671 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6672 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6673 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6674 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6675 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6676 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6677 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6678 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6679 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6680 {
6681 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6682 /* .name = "Capture Source", */
6683 .name = "Input Source",
6684 .count = 2,
6685 .info = alc883_mux_enum_info,
6686 .get = alc883_mux_enum_get,
6687 .put = alc883_mux_enum_put,
6688 },
6689 { } /* end */
6690};
6691
Jiang zhefb97dc62008-03-06 11:07:11 +01006692static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
6693 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6694 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
6695 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6696 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
6697 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6698 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6699 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6700 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6701 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6702 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6703 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6704 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6705 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6706 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6707 {
6708 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6709 /* .name = "Capture Source", */
6710 .name = "Input Source",
6711 .count = 2,
6712 .info = alc883_mux_enum_info,
6713 .get = alc883_mux_enum_get,
6714 .put = alc883_mux_enum_put,
6715 },
6716 { } /* end */
6717};
6718
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006719static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6720 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6721 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6722 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6723 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6724 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6725 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6726 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6727 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006728 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006729 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6730 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006731 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006732 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6733 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6734 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6735 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6736 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6737 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6738 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6739 {
6740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6741 /* .name = "Capture Source", */
6742 .name = "Input Source",
6743 .count = 2,
6744 .info = alc883_mux_enum_info,
6745 .get = alc883_mux_enum_get,
6746 .put = alc883_mux_enum_put,
6747 },
6748 { } /* end */
6749};
6750
6751static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6752 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6753 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6754 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6755 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6756 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6757 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6758 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6759 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6760 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6761 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6762 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6763 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6764 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6765 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006766 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006767 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6768 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006769 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006770 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6771 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6772 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6773 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6774 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6775 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6776 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6777 {
6778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6779 /* .name = "Capture Source", */
6780 .name = "Input Source",
6781 .count = 2,
6782 .info = alc883_mux_enum_info,
6783 .get = alc883_mux_enum_get,
6784 .put = alc883_mux_enum_put,
6785 },
6786 { } /* end */
6787};
6788
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006789static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006790 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6791 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6792 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6793 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6794 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6795 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6796 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6797 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6798 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6799 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6800 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6801 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6802 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6803 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006804 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006805 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6806 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006807 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006808 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6809 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6810 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6811 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6812 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6813
6814 {
6815 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6816 /* .name = "Capture Source", */
6817 .name = "Input Source",
6818 .count = 1,
6819 .info = alc883_mux_enum_info,
6820 .get = alc883_mux_enum_get,
6821 .put = alc883_mux_enum_put,
6822 },
6823 { } /* end */
6824};
6825
Kailang Yangccc656c2006-10-17 12:32:26 +02006826static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6827 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6828 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6829 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6830 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6831 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6832 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6833 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6834 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6835 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6836 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6837 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6838 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6839 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6840 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006841 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006842 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6843 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6844 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6845 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6846 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6847 {
6848 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6849 /* .name = "Capture Source", */
6850 .name = "Input Source",
6851 .count = 2,
6852 .info = alc883_mux_enum_info,
6853 .get = alc883_mux_enum_get,
6854 .put = alc883_mux_enum_put,
6855 },
6856 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006857};
Kailang Yangccc656c2006-10-17 12:32:26 +02006858
6859static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6860 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6861 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6862 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6863 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6864 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6865 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006866 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006867 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02006868 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6869 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6870 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006871 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6872 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6873 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6874 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6875 {
6876 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6877 /* .name = "Capture Source", */
6878 .name = "Input Source",
6879 .count = 2,
6880 .info = alc883_mux_enum_info,
6881 .get = alc883_mux_enum_get,
6882 .put = alc883_mux_enum_put,
6883 },
6884 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006885};
Kailang Yangccc656c2006-10-17 12:32:26 +02006886
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006887static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6888 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6889 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006890 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6891 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006892 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6893 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6894 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6895 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6896 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6897 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6898 {
6899 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6900 /* .name = "Capture Source", */
6901 .name = "Input Source",
6902 .count = 1,
6903 .info = alc883_mux_enum_info,
6904 .get = alc883_mux_enum_get,
6905 .put = alc883_mux_enum_put,
6906 },
6907 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006908};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006909
Kailang Yang272a5272007-05-14 11:00:38 +02006910static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
6911 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6912 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
6913 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6914 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6915 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6916 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6917 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6918 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6919 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6920 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6921 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6922 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6923 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6924 {
6925 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6926 /* .name = "Capture Source", */
6927 .name = "Input Source",
6928 .count = 2,
6929 .info = alc883_mux_enum_info,
6930 .get = alc883_mux_enum_get,
6931 .put = alc883_mux_enum_put,
6932 },
6933 { } /* end */
6934};
6935
6936static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
6937 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6938 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6939 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6940 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6941 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6942 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6943 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6944 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6945 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6946 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6947 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6948 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6949 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6950 {
6951 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6952 /* .name = "Capture Source", */
6953 .name = "Input Source",
6954 .count = 2,
6955 .info = alc883_mux_enum_info,
6956 .get = alc883_mux_enum_get,
6957 .put = alc883_mux_enum_put,
6958 },
6959 { } /* end */
6960};
6961
Tobin Davis2880a862007-08-07 11:50:26 +02006962static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02006963 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6964 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006965 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006966 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6967 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02006968 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6969 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6970 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006971 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6972 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6973 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6974 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6975 {
6976 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6977 /* .name = "Capture Source", */
6978 .name = "Input Source",
6979 .count = 2,
6980 .info = alc883_mux_enum_info,
6981 .get = alc883_mux_enum_get,
6982 .put = alc883_mux_enum_put,
6983 },
6984 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02006985};
Tobin Davis2880a862007-08-07 11:50:26 +02006986
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006987static struct snd_kcontrol_new alc883_chmode_mixer[] = {
6988 {
6989 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6990 .name = "Channel Mode",
6991 .info = alc_ch_mode_info,
6992 .get = alc_ch_mode_get,
6993 .put = alc_ch_mode_put,
6994 },
6995 { } /* end */
6996};
6997
6998static struct hda_verb alc883_init_verbs[] = {
6999 /* ADC1: mute amp left and right */
7000 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7001 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7002 /* ADC2: mute amp left and right */
7003 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7004 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7005 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7006 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7007 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7008 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7009 /* Rear mixer */
7010 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7011 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7012 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7013 /* CLFE mixer */
7014 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7015 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7016 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7017 /* Side mixer */
7018 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7019 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7020 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7021
Takashi Iwaicb53c622007-08-10 17:21:45 +02007022 /* mute analog input loopbacks */
7023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7025 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7026 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7027 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007028
7029 /* Front Pin: output 0 (0x0c) */
7030 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7031 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7032 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7033 /* Rear Pin: output 1 (0x0d) */
7034 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7035 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7036 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7037 /* CLFE Pin: output 2 (0x0e) */
7038 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7039 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7040 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7041 /* Side Pin: output 3 (0x0f) */
7042 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7043 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7044 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7045 /* Mic (rear) pin: input vref at 80% */
7046 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7047 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7048 /* Front Mic pin: input vref at 80% */
7049 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7050 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7051 /* Line In pin: input */
7052 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7053 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7054 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7055 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7056 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7057 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7058 /* CD pin widget for input */
7059 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7060
7061 /* FIXME: use matrix-type input source selection */
7062 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7063 /* Input mixer2 */
7064 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7065 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7066 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7067 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7068 /* Input mixer3 */
7069 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7070 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7071 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7072 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7073 { }
7074};
7075
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007076/* toggle speaker-output according to the hp-jack state */
7077static void alc883_mitac_hp_automute(struct hda_codec *codec)
7078{
7079 unsigned int present;
7080
7081 present = snd_hda_codec_read(codec, 0x15, 0,
7082 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7083 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7084 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7085 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7086 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7087}
7088
7089/* auto-toggle front mic */
7090/*
7091static void alc883_mitac_mic_automute(struct hda_codec *codec)
7092{
7093 unsigned int present;
7094 unsigned char bits;
7095
7096 present = snd_hda_codec_read(codec, 0x18, 0,
7097 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7098 bits = present ? HDA_AMP_MUTE : 0;
7099 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7100}
7101*/
7102
7103static void alc883_mitac_automute(struct hda_codec *codec)
7104{
7105 alc883_mitac_hp_automute(codec);
7106 /* alc883_mitac_mic_automute(codec); */
7107}
7108
7109static void alc883_mitac_unsol_event(struct hda_codec *codec,
7110 unsigned int res)
7111{
7112 switch (res >> 26) {
7113 case ALC880_HP_EVENT:
7114 alc883_mitac_hp_automute(codec);
7115 break;
7116 case ALC880_MIC_EVENT:
7117 /* alc883_mitac_mic_automute(codec); */
7118 break;
7119 }
7120}
7121
7122static struct hda_verb alc883_mitac_verbs[] = {
7123 /* HP */
7124 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7125 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7126 /* Subwoofer */
7127 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7128 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7129
7130 /* enable unsolicited event */
7131 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7132 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7133
7134 { } /* end */
7135};
7136
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007137static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007138 /* HP */
7139 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7140 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7141 /* Int speaker */
7142 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7143 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7144
7145 /* enable unsolicited event */
7146 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007147 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007148
7149 { } /* end */
7150};
7151
Jiang zhefb97dc62008-03-06 11:07:11 +01007152static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7153 /* HP */
7154 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7155 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7156 /* Subwoofer */
7157 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7158 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7159
7160 /* enable unsolicited event */
7161 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7162
7163 { } /* end */
7164};
7165
Kailang Yangccc656c2006-10-17 12:32:26 +02007166static struct hda_verb alc883_tagra_verbs[] = {
7167 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7168 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7169
7170 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7171 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7172
7173 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7174 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7175 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7176
7177 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007178 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7179 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7180 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007181
7182 { } /* end */
7183};
7184
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007185static struct hda_verb alc883_lenovo_101e_verbs[] = {
7186 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7187 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7188 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7189 { } /* end */
7190};
7191
Kailang Yang272a5272007-05-14 11:00:38 +02007192static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7193 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7194 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7195 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7196 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7197 { } /* end */
7198};
7199
7200static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7201 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7202 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7203 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7204 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7205 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7206 { } /* end */
7207};
7208
Kailang Yang189609a2007-08-20 11:31:23 +02007209static struct hda_verb alc883_haier_w66_verbs[] = {
7210 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7211 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7212
7213 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7214
7215 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7216 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7217 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7218 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7219 { } /* end */
7220};
7221
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007222static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007223 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007224 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7225 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007226 { }
7227};
7228
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007229static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007230 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7231 { }
7232};
7233
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007234static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007235 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7236 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7237 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7238 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7239 { }
7240};
7241
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007242static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007243 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7244 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7245 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7246 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7247 { }
7248};
7249
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007250static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7251 { 2, alc888_3st_hp_2ch_init },
7252 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007253};
7254
Kailang Yang272a5272007-05-14 11:00:38 +02007255/* toggle front-jack and RCA according to the hp-jack state */
7256static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7257{
7258 unsigned int present;
7259
7260 present = snd_hda_codec_read(codec, 0x1b, 0,
7261 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007262 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7263 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7264 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7265 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007266}
7267
7268/* toggle RCA according to the front-jack state */
7269static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7270{
7271 unsigned int present;
7272
7273 present = snd_hda_codec_read(codec, 0x14, 0,
7274 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007275 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7276 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007277}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007278
Kailang Yang272a5272007-05-14 11:00:38 +02007279static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7280 unsigned int res)
7281{
7282 if ((res >> 26) == ALC880_HP_EVENT)
7283 alc888_lenovo_ms7195_front_automute(codec);
7284 if ((res >> 26) == ALC880_FRONT_EVENT)
7285 alc888_lenovo_ms7195_rca_automute(codec);
7286}
7287
7288static struct hda_verb alc883_medion_md2_verbs[] = {
7289 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7290 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7291
7292 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7293
7294 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7295 { } /* end */
7296};
7297
7298/* toggle speaker-output according to the hp-jack state */
7299static void alc883_medion_md2_automute(struct hda_codec *codec)
7300{
7301 unsigned int present;
7302
7303 present = snd_hda_codec_read(codec, 0x14, 0,
7304 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007305 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7306 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007307}
7308
7309static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7310 unsigned int res)
7311{
7312 if ((res >> 26) == ALC880_HP_EVENT)
7313 alc883_medion_md2_automute(codec);
7314}
7315
Kailang Yangccc656c2006-10-17 12:32:26 +02007316/* toggle speaker-output according to the hp-jack state */
7317static void alc883_tagra_automute(struct hda_codec *codec)
7318{
7319 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007320 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007321
7322 present = snd_hda_codec_read(codec, 0x14, 0,
7323 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007324 bits = present ? HDA_AMP_MUTE : 0;
7325 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7326 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007327 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7328 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007329}
7330
7331static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7332{
7333 if ((res >> 26) == ALC880_HP_EVENT)
7334 alc883_tagra_automute(codec);
7335}
7336
Jiang zhe368c7a92008-03-04 11:20:33 +01007337/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007338static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007339{
7340 unsigned int present;
7341 unsigned char bits;
7342
7343 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7344 & AC_PINSENSE_PRESENCE;
7345 bits = present ? HDA_AMP_MUTE : 0;
7346 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7347 HDA_AMP_MUTE, bits);
7348}
7349
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007350static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7351{
7352 unsigned int present;
7353
7354 present = snd_hda_codec_read(codec, 0x18, 0,
7355 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7356 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7357 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7358}
7359
7360static void alc883_clevo_m720_automute(struct hda_codec *codec)
7361{
7362 alc883_clevo_m720_hp_automute(codec);
7363 alc883_clevo_m720_mic_automute(codec);
7364}
7365
7366static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007367 unsigned int res)
7368{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007369 switch (res >> 26) {
7370 case ALC880_HP_EVENT:
7371 alc883_clevo_m720_hp_automute(codec);
7372 break;
7373 case ALC880_MIC_EVENT:
7374 alc883_clevo_m720_mic_automute(codec);
7375 break;
7376 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007377}
7378
Jiang zhefb97dc62008-03-06 11:07:11 +01007379/* toggle speaker-output according to the hp-jack state */
7380static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7381{
7382 unsigned int present;
7383 unsigned char bits;
7384
7385 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7386 & AC_PINSENSE_PRESENCE;
7387 bits = present ? HDA_AMP_MUTE : 0;
7388 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7389 HDA_AMP_MUTE, bits);
7390}
7391
7392static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7393 unsigned int res)
7394{
7395 if ((res >> 26) == ALC880_HP_EVENT)
7396 alc883_2ch_fujitsu_pi2515_automute(codec);
7397}
7398
Kailang Yang189609a2007-08-20 11:31:23 +02007399static void alc883_haier_w66_automute(struct hda_codec *codec)
7400{
7401 unsigned int present;
7402 unsigned char bits;
7403
7404 present = snd_hda_codec_read(codec, 0x1b, 0,
7405 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7406 bits = present ? 0x80 : 0;
7407 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7408 0x80, bits);
7409}
7410
7411static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7412 unsigned int res)
7413{
7414 if ((res >> 26) == ALC880_HP_EVENT)
7415 alc883_haier_w66_automute(codec);
7416}
7417
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007418static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7419{
7420 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007421 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007422
7423 present = snd_hda_codec_read(codec, 0x14, 0,
7424 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007425 bits = present ? HDA_AMP_MUTE : 0;
7426 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7427 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007428}
7429
7430static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7431{
7432 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007433 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007434
7435 present = snd_hda_codec_read(codec, 0x1b, 0,
7436 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007437 bits = present ? HDA_AMP_MUTE : 0;
7438 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7439 HDA_AMP_MUTE, bits);
7440 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7441 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007442}
7443
7444static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7445 unsigned int res)
7446{
7447 if ((res >> 26) == ALC880_HP_EVENT)
7448 alc883_lenovo_101e_all_automute(codec);
7449 if ((res >> 26) == ALC880_FRONT_EVENT)
7450 alc883_lenovo_101e_ispeaker_automute(codec);
7451}
7452
Takashi Iwai676a9b52007-08-16 15:23:35 +02007453/* toggle speaker-output according to the hp-jack state */
7454static void alc883_acer_aspire_automute(struct hda_codec *codec)
7455{
7456 unsigned int present;
7457
7458 present = snd_hda_codec_read(codec, 0x14, 0,
7459 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7460 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7461 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7462 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7463 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7464}
7465
7466static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7467 unsigned int res)
7468{
7469 if ((res >> 26) == ALC880_HP_EVENT)
7470 alc883_acer_aspire_automute(codec);
7471}
7472
Kailang Yangd1a991a2007-08-15 16:21:59 +02007473static struct hda_verb alc883_acer_eapd_verbs[] = {
7474 /* HP Pin: output 0 (0x0c) */
7475 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7476 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7477 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7478 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007479 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7480 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007481 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007482 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7483 /* eanable EAPD on medion laptop */
7484 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7485 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007486 /* enable unsolicited event */
7487 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007488 { }
7489};
7490
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007491static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7492{
7493 unsigned int present;
7494
7495 present = snd_hda_codec_read(codec, 0x1b, 0,
7496 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7497 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7498 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7499 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7500 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7501 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7502 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7503 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7504 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7505}
7506
7507static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7508 unsigned int res)
7509{
7510 switch (res >> 26) {
7511 case ALC880_HP_EVENT:
7512 printk("hp_event\n");
7513 alc888_6st_dell_front_automute(codec);
7514 break;
7515 }
7516}
7517
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007518/*
7519 * generic initialization of ADC, input mixers and output mixers
7520 */
7521static struct hda_verb alc883_auto_init_verbs[] = {
7522 /*
7523 * Unmute ADC0-2 and set the default input to mic-in
7524 */
7525 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7526 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7527 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7528 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7529
Takashi Iwaicb53c622007-08-10 17:21:45 +02007530 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007531 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007532 * Note: PASD motherboards uses the Line In 2 as the input for
7533 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007534 */
7535 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007536 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7537 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7538 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7539 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7540 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007541
7542 /*
7543 * Set up output mixers (0x0c - 0x0f)
7544 */
7545 /* set vol=0 to output mixers */
7546 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7547 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7548 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7549 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7550 /* set up input amps for analog loopback */
7551 /* Amp Indices: DAC = 0, mixer = 1 */
7552 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7553 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7554 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7555 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7556 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7557 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7558 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7559 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7560 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7561 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7562
7563 /* FIXME: use matrix-type input source selection */
7564 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7565 /* Input mixer1 */
7566 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7567 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7568 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007569 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007570 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7571 /* Input mixer2 */
7572 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7573 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7574 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007575 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007576 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007577
7578 { }
7579};
7580
7581/* capture mixer elements */
7582static struct snd_kcontrol_new alc883_capture_mixer[] = {
7583 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7584 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7585 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7586 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7587 {
7588 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7589 /* The multiple "Capture Source" controls confuse alsamixer
7590 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007591 */
7592 /* .name = "Capture Source", */
7593 .name = "Input Source",
7594 .count = 2,
7595 .info = alc882_mux_enum_info,
7596 .get = alc882_mux_enum_get,
7597 .put = alc882_mux_enum_put,
7598 },
7599 { } /* end */
7600};
7601
Takashi Iwaicb53c622007-08-10 17:21:45 +02007602#ifdef CONFIG_SND_HDA_POWER_SAVE
7603#define alc883_loopbacks alc880_loopbacks
7604#endif
7605
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007606/* pcm configuration: identiacal with ALC880 */
7607#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7608#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01007609#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007610#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7611#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7612
7613/*
7614 * configuration and preset
7615 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007616static const char *alc883_models[ALC883_MODEL_LAST] = {
7617 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7618 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7619 [ALC883_3ST_6ch] = "3stack-6ch",
7620 [ALC883_6ST_DIG] = "6stack-dig",
7621 [ALC883_TARGA_DIG] = "targa-dig",
7622 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007623 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007624 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007625 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007626 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007627 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007628 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007629 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7630 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007631 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007632 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007633 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007634 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007635 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01007636 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007637 [ALC883_AUTO] = "auto",
7638};
7639
7640static struct snd_pci_quirk alc883_cfg_tbl[] = {
7641 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007642 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7643 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7644 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7645 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007646 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02007647 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007648 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7649 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01007650 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007651 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007652 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007653 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7654 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7655 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007656 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007657 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7658 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7659 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02007660 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007661 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01007662 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007663 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7664 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7665 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7666 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7667 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7668 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7669 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7670 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7671 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007672 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7673 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007674 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01007675 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007676 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007677 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007678 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007679 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007680 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
7681 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007682 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007683 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007684 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01007685 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02007686 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007687 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007688 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7689 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007690 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01007691 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02007692 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007693 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007694 {}
7695};
7696
7697static struct alc_config_preset alc883_presets[] = {
7698 [ALC883_3ST_2ch_DIG] = {
7699 .mixers = { alc883_3ST_2ch_mixer },
7700 .init_verbs = { alc883_init_verbs },
7701 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7702 .dac_nids = alc883_dac_nids,
7703 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007704 .dig_in_nid = ALC883_DIGIN_NID,
7705 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7706 .channel_mode = alc883_3ST_2ch_modes,
7707 .input_mux = &alc883_capture_source,
7708 },
7709 [ALC883_3ST_6ch_DIG] = {
7710 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7711 .init_verbs = { alc883_init_verbs },
7712 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7713 .dac_nids = alc883_dac_nids,
7714 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007715 .dig_in_nid = ALC883_DIGIN_NID,
7716 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7717 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007718 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007719 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007720 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007721 [ALC883_3ST_6ch] = {
7722 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7723 .init_verbs = { alc883_init_verbs },
7724 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7725 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007726 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7727 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007728 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007729 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007730 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007731 [ALC883_6ST_DIG] = {
7732 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7733 .init_verbs = { alc883_init_verbs },
7734 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7735 .dac_nids = alc883_dac_nids,
7736 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007737 .dig_in_nid = ALC883_DIGIN_NID,
7738 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7739 .channel_mode = alc883_sixstack_modes,
7740 .input_mux = &alc883_capture_source,
7741 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007742 [ALC883_TARGA_DIG] = {
7743 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7744 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7745 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7746 .dac_nids = alc883_dac_nids,
7747 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007748 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7749 .channel_mode = alc883_3ST_6ch_modes,
7750 .need_dac_fix = 1,
7751 .input_mux = &alc883_capture_source,
7752 .unsol_event = alc883_tagra_unsol_event,
7753 .init_hook = alc883_tagra_automute,
7754 },
7755 [ALC883_TARGA_2ch_DIG] = {
7756 .mixers = { alc883_tagra_2ch_mixer},
7757 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7758 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7759 .dac_nids = alc883_dac_nids,
7760 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007761 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7762 .channel_mode = alc883_3ST_2ch_modes,
7763 .input_mux = &alc883_capture_source,
7764 .unsol_event = alc883_tagra_unsol_event,
7765 .init_hook = alc883_tagra_automute,
7766 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007767 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007768 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007769 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7770 * and the headphone jack. Turn this on and rely on the
7771 * standard mute methods whenever the user wants to turn
7772 * these outputs off.
7773 */
7774 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7775 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7776 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007777 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7778 .channel_mode = alc883_3ST_2ch_modes,
7779 .input_mux = &alc883_capture_source,
7780 },
Tobin Davis2880a862007-08-07 11:50:26 +02007781 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007782 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007783 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007784 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7785 .dac_nids = alc883_dac_nids,
7786 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02007787 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7788 .channel_mode = alc883_3ST_2ch_modes,
7789 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007790 .unsol_event = alc883_acer_aspire_unsol_event,
7791 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007792 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007793 [ALC883_MEDION] = {
7794 .mixers = { alc883_fivestack_mixer,
7795 alc883_chmode_mixer },
7796 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007797 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007798 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7799 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02007800 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7801 .channel_mode = alc883_sixstack_modes,
7802 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007803 },
Kailang Yang272a5272007-05-14 11:00:38 +02007804 [ALC883_MEDION_MD2] = {
7805 .mixers = { alc883_medion_md2_mixer},
7806 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7807 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7808 .dac_nids = alc883_dac_nids,
7809 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007810 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7811 .channel_mode = alc883_3ST_2ch_modes,
7812 .input_mux = &alc883_capture_source,
7813 .unsol_event = alc883_medion_md2_unsol_event,
7814 .init_hook = alc883_medion_md2_automute,
7815 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007816 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007817 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007818 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7819 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7820 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007821 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7822 .channel_mode = alc883_3ST_2ch_modes,
7823 .input_mux = &alc883_capture_source,
7824 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007825 [ALC883_CLEVO_M720] = {
7826 .mixers = { alc883_clevo_m720_mixer },
7827 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01007828 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7829 .dac_nids = alc883_dac_nids,
7830 .dig_out_nid = ALC883_DIGOUT_NID,
7831 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7832 .channel_mode = alc883_3ST_2ch_modes,
7833 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007834 .unsol_event = alc883_clevo_m720_unsol_event,
7835 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01007836 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007837 [ALC883_LENOVO_101E_2ch] = {
7838 .mixers = { alc883_lenovo_101e_2ch_mixer},
7839 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7840 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7841 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007842 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7843 .channel_mode = alc883_3ST_2ch_modes,
7844 .input_mux = &alc883_lenovo_101e_capture_source,
7845 .unsol_event = alc883_lenovo_101e_unsol_event,
7846 .init_hook = alc883_lenovo_101e_all_automute,
7847 },
Kailang Yang272a5272007-05-14 11:00:38 +02007848 [ALC883_LENOVO_NB0763] = {
7849 .mixers = { alc883_lenovo_nb0763_mixer },
7850 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7851 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7852 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007853 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7854 .channel_mode = alc883_3ST_2ch_modes,
7855 .need_dac_fix = 1,
7856 .input_mux = &alc883_lenovo_nb0763_capture_source,
7857 .unsol_event = alc883_medion_md2_unsol_event,
7858 .init_hook = alc883_medion_md2_automute,
7859 },
7860 [ALC888_LENOVO_MS7195_DIG] = {
7861 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7862 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7863 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7864 .dac_nids = alc883_dac_nids,
7865 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007866 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7867 .channel_mode = alc883_3ST_6ch_modes,
7868 .need_dac_fix = 1,
7869 .input_mux = &alc883_capture_source,
7870 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7871 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007872 },
7873 [ALC883_HAIER_W66] = {
7874 .mixers = { alc883_tagra_2ch_mixer},
7875 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7876 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7877 .dac_nids = alc883_dac_nids,
7878 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02007879 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7880 .channel_mode = alc883_3ST_2ch_modes,
7881 .input_mux = &alc883_capture_source,
7882 .unsol_event = alc883_haier_w66_unsol_event,
7883 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01007884 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007885 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01007886 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007887 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007888 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7889 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007890 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7891 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007892 .need_dac_fix = 1,
7893 .input_mux = &alc883_capture_source,
7894 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007895 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01007896 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007897 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
7898 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7899 .dac_nids = alc883_dac_nids,
7900 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007901 .dig_in_nid = ALC883_DIGIN_NID,
7902 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7903 .channel_mode = alc883_sixstack_modes,
7904 .input_mux = &alc883_capture_source,
7905 .unsol_event = alc888_6st_dell_unsol_event,
7906 .init_hook = alc888_6st_dell_front_automute,
7907 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007908 [ALC883_MITAC] = {
7909 .mixers = { alc883_mitac_mixer },
7910 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
7911 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7912 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007913 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7914 .channel_mode = alc883_3ST_2ch_modes,
7915 .input_mux = &alc883_capture_source,
7916 .unsol_event = alc883_mitac_unsol_event,
7917 .init_hook = alc883_mitac_automute,
7918 },
Jiang zhefb97dc62008-03-06 11:07:11 +01007919 [ALC883_FUJITSU_PI2515] = {
7920 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
7921 .init_verbs = { alc883_init_verbs,
7922 alc883_2ch_fujitsu_pi2515_verbs},
7923 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7924 .dac_nids = alc883_dac_nids,
7925 .dig_out_nid = ALC883_DIGOUT_NID,
7926 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7927 .channel_mode = alc883_3ST_2ch_modes,
7928 .input_mux = &alc883_fujitsu_pi2515_capture_source,
7929 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
7930 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
7931 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007932};
7933
7934
7935/*
7936 * BIOS auto configuration
7937 */
7938static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
7939 hda_nid_t nid, int pin_type,
7940 int dac_idx)
7941{
7942 /* set as output */
7943 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007944 int idx;
7945
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007946 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007947 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7948 idx = 4;
7949 else
7950 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007951 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7952
7953}
7954
7955static void alc883_auto_init_multi_out(struct hda_codec *codec)
7956{
7957 struct alc_spec *spec = codec->spec;
7958 int i;
7959
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007960 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007961 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007962 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007963 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007964 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007965 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007966 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007967 }
7968}
7969
7970static void alc883_auto_init_hp_out(struct hda_codec *codec)
7971{
7972 struct alc_spec *spec = codec->spec;
7973 hda_nid_t pin;
7974
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007975 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007976 if (pin) /* connect to front */
7977 /* use dac 0 */
7978 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007979 pin = spec->autocfg.speaker_pins[0];
7980 if (pin)
7981 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007982}
7983
7984#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
7985#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
7986
7987static void alc883_auto_init_analog_input(struct hda_codec *codec)
7988{
7989 struct alc_spec *spec = codec->spec;
7990 int i;
7991
7992 for (i = 0; i < AUTO_PIN_LAST; i++) {
7993 hda_nid_t nid = spec->autocfg.input_pins[i];
7994 if (alc883_is_input_pin(nid)) {
7995 snd_hda_codec_write(codec, nid, 0,
7996 AC_VERB_SET_PIN_WIDGET_CONTROL,
7997 (i <= AUTO_PIN_FRONT_MIC ?
7998 PIN_VREF80 : PIN_IN));
7999 if (nid != ALC883_PIN_CD_NID)
8000 snd_hda_codec_write(codec, nid, 0,
8001 AC_VERB_SET_AMP_GAIN_MUTE,
8002 AMP_OUT_MUTE);
8003 }
8004 }
8005}
8006
8007/* almost identical with ALC880 parser... */
8008static int alc883_parse_auto_config(struct hda_codec *codec)
8009{
8010 struct alc_spec *spec = codec->spec;
8011 int err = alc880_parse_auto_config(codec);
8012
8013 if (err < 0)
8014 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008015 else if (!err)
8016 return 0; /* no config found */
8017
8018 err = alc_auto_add_mic_boost(codec);
8019 if (err < 0)
8020 return err;
8021
8022 /* hack - override the init verbs */
8023 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008024 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
8025 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02008026
8027 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008028}
8029
8030/* additional initialization for auto-configuration model */
8031static void alc883_auto_init(struct hda_codec *codec)
8032{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008033 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008034 alc883_auto_init_multi_out(codec);
8035 alc883_auto_init_hp_out(codec);
8036 alc883_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008037 if (spec->unsol_event)
8038 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008039}
8040
8041static int patch_alc883(struct hda_codec *codec)
8042{
8043 struct alc_spec *spec;
8044 int err, board_config;
8045
8046 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8047 if (spec == NULL)
8048 return -ENOMEM;
8049
8050 codec->spec = spec;
8051
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008052 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8053 alc883_models,
8054 alc883_cfg_tbl);
8055 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008056 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8057 "trying auto-probe from BIOS...\n");
8058 board_config = ALC883_AUTO;
8059 }
8060
8061 if (board_config == ALC883_AUTO) {
8062 /* automatic parse from the BIOS config */
8063 err = alc883_parse_auto_config(codec);
8064 if (err < 0) {
8065 alc_free(codec);
8066 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008067 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008068 printk(KERN_INFO
8069 "hda_codec: Cannot set up configuration "
8070 "from BIOS. Using base mode...\n");
8071 board_config = ALC883_3ST_2ch_DIG;
8072 }
8073 }
8074
8075 if (board_config != ALC883_AUTO)
8076 setup_preset(spec, &alc883_presets[board_config]);
8077
8078 spec->stream_name_analog = "ALC883 Analog";
8079 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8080 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008081 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008082
8083 spec->stream_name_digital = "ALC883 Digital";
8084 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8085 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8086
Takashi Iwaie1406342008-02-11 18:32:32 +01008087 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8088 spec->adc_nids = alc883_adc_nids;
8089 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008090
Takashi Iwai2134ea42008-01-10 16:53:55 +01008091 spec->vmaster_nid = 0x0c;
8092
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008093 codec->patch_ops = alc_patch_ops;
8094 if (board_config == ALC883_AUTO)
8095 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02008096#ifdef CONFIG_SND_HDA_POWER_SAVE
8097 if (!spec->loopback.amplist)
8098 spec->loopback.amplist = alc883_loopbacks;
8099#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008100
8101 return 0;
8102}
8103
8104/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008105 * ALC262 support
8106 */
8107
8108#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8109#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8110
8111#define alc262_dac_nids alc260_dac_nids
8112#define alc262_adc_nids alc882_adc_nids
8113#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008114#define alc262_capsrc_nids alc882_capsrc_nids
8115#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008116
8117#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008118#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008119
8120static struct snd_kcontrol_new alc262_base_mixer[] = {
8121 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8122 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8123 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8124 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8125 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8126 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8128 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008129 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008130 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8131 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008132 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008133 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008134 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008135 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8136 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8137 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8138 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008139 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008140};
8141
Kailang Yangccc656c2006-10-17 12:32:26 +02008142static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8143 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8144 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8145 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8146 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8147 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8148 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8149 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8150 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008151 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008152 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8153 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008154 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008155 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008156 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008157 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8158 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8159 { } /* end */
8160};
8161
Takashi Iwaice875f02008-01-28 18:17:43 +01008162/* update HP, line and mono-out pins according to the master switch */
8163static void alc262_hp_master_update(struct hda_codec *codec)
8164{
8165 struct alc_spec *spec = codec->spec;
8166 int val = spec->master_sw;
8167
8168 /* HP & line-out */
8169 snd_hda_codec_write_cache(codec, 0x1b, 0,
8170 AC_VERB_SET_PIN_WIDGET_CONTROL,
8171 val ? PIN_HP : 0);
8172 snd_hda_codec_write_cache(codec, 0x15, 0,
8173 AC_VERB_SET_PIN_WIDGET_CONTROL,
8174 val ? PIN_HP : 0);
8175 /* mono (speaker) depending on the HP jack sense */
8176 val = val && !spec->jack_present;
8177 snd_hda_codec_write_cache(codec, 0x16, 0,
8178 AC_VERB_SET_PIN_WIDGET_CONTROL,
8179 val ? PIN_OUT : 0);
8180}
8181
8182static void alc262_hp_bpc_automute(struct hda_codec *codec)
8183{
8184 struct alc_spec *spec = codec->spec;
8185 unsigned int presence;
8186 presence = snd_hda_codec_read(codec, 0x1b, 0,
8187 AC_VERB_GET_PIN_SENSE, 0);
8188 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8189 alc262_hp_master_update(codec);
8190}
8191
8192static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8193{
8194 if ((res >> 26) != ALC880_HP_EVENT)
8195 return;
8196 alc262_hp_bpc_automute(codec);
8197}
8198
8199static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8200{
8201 struct alc_spec *spec = codec->spec;
8202 unsigned int presence;
8203 presence = snd_hda_codec_read(codec, 0x15, 0,
8204 AC_VERB_GET_PIN_SENSE, 0);
8205 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8206 alc262_hp_master_update(codec);
8207}
8208
8209static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8210 unsigned int res)
8211{
8212 if ((res >> 26) != ALC880_HP_EVENT)
8213 return;
8214 alc262_hp_wildwest_automute(codec);
8215}
8216
8217static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8218 struct snd_ctl_elem_value *ucontrol)
8219{
8220 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8221 struct alc_spec *spec = codec->spec;
8222 *ucontrol->value.integer.value = spec->master_sw;
8223 return 0;
8224}
8225
8226static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8227 struct snd_ctl_elem_value *ucontrol)
8228{
8229 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8230 struct alc_spec *spec = codec->spec;
8231 int val = !!*ucontrol->value.integer.value;
8232
8233 if (val == spec->master_sw)
8234 return 0;
8235 spec->master_sw = val;
8236 alc262_hp_master_update(codec);
8237 return 1;
8238}
8239
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008240static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008241 {
8242 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8243 .name = "Master Playback Switch",
8244 .info = snd_ctl_boolean_mono_info,
8245 .get = alc262_hp_master_sw_get,
8246 .put = alc262_hp_master_sw_put,
8247 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8249 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8250 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008251 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8252 HDA_OUTPUT),
8253 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8254 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008255 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8256 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008257 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008258 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8259 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008260 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008261 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8262 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8263 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8264 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8265 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8266 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8267 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8268 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8269 { } /* end */
8270};
8271
Kailang Yangcd7509a2007-01-26 18:33:17 +01008272static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008273 {
8274 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8275 .name = "Master Playback Switch",
8276 .info = snd_ctl_boolean_mono_info,
8277 .get = alc262_hp_master_sw_get,
8278 .put = alc262_hp_master_sw_put,
8279 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008280 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8281 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8282 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8283 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008284 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8285 HDA_OUTPUT),
8286 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8287 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008288 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8289 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008290 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008291 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8292 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8293 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8294 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8295 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8296 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8297 { } /* end */
8298};
8299
8300static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8301 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8302 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008303 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008304 { } /* end */
8305};
8306
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008307/* mute/unmute internal speaker according to the hp jack and mute state */
8308static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8309{
8310 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008311
8312 if (force || !spec->sense_updated) {
8313 unsigned int present;
8314 present = snd_hda_codec_read(codec, 0x15, 0,
8315 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008316 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008317 spec->sense_updated = 1;
8318 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008319 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8320 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008321}
8322
8323static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8324 unsigned int res)
8325{
8326 if ((res >> 26) != ALC880_HP_EVENT)
8327 return;
8328 alc262_hp_t5735_automute(codec, 1);
8329}
8330
8331static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8332{
8333 alc262_hp_t5735_automute(codec, 1);
8334}
8335
8336static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008337 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8338 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008339 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8340 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8341 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8342 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8343 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8344 { } /* end */
8345};
8346
8347static struct hda_verb alc262_hp_t5735_verbs[] = {
8348 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8349 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8350
8351 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8352 { }
8353};
8354
Kailang Yang8c427222008-01-10 13:03:59 +01008355static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01008356 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8357 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008358 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8359 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01008360 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8361 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8362 { } /* end */
8363};
8364
8365static struct hda_verb alc262_hp_rp5700_verbs[] = {
8366 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8367 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8368 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8369 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8370 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8371 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8372 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8373 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8374 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8376 {}
8377};
8378
8379static struct hda_input_mux alc262_hp_rp5700_capture_source = {
8380 .num_items = 1,
8381 .items = {
8382 { "Line", 0x1 },
8383 },
8384};
8385
Takashi Iwai0724ea22007-08-23 00:31:43 +02008386/* bind hp and internal speaker mute (with plug check) */
8387static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
8388 struct snd_ctl_elem_value *ucontrol)
8389{
8390 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8391 long *valp = ucontrol->value.integer.value;
8392 int change;
8393
8394 /* change hp mute */
8395 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
8396 HDA_AMP_MUTE,
8397 valp[0] ? 0 : HDA_AMP_MUTE);
8398 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
8399 HDA_AMP_MUTE,
8400 valp[1] ? 0 : HDA_AMP_MUTE);
8401 if (change) {
8402 /* change speaker according to HP jack state */
8403 struct alc_spec *spec = codec->spec;
8404 unsigned int mute;
8405 if (spec->jack_present)
8406 mute = HDA_AMP_MUTE;
8407 else
8408 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
8409 HDA_OUTPUT, 0);
8410 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8411 HDA_AMP_MUTE, mute);
8412 }
8413 return change;
8414}
Takashi Iwai5b319542007-07-26 11:49:22 +02008415
Kailang Yang272a5272007-05-14 11:00:38 +02008416static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02008417 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8418 {
8419 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8420 .name = "Master Playback Switch",
8421 .info = snd_hda_mixer_amp_switch_info,
8422 .get = snd_hda_mixer_amp_switch_get,
8423 .put = alc262_sony_master_sw_put,
8424 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8425 },
Kailang Yang272a5272007-05-14 11:00:38 +02008426 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8427 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8428 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8429 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8430 { } /* end */
8431};
8432
Kailang Yang83c34212007-07-05 11:43:05 +02008433static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8434 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8435 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8436 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8437 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8438 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8439 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8440 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8441 { } /* end */
8442};
Kailang Yang272a5272007-05-14 11:00:38 +02008443
Kailang Yangdf694da2005-12-05 19:42:22 +01008444#define alc262_capture_mixer alc882_capture_mixer
8445#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8446
8447/*
8448 * generic initialization of ADC, input mixers and output mixers
8449 */
8450static struct hda_verb alc262_init_verbs[] = {
8451 /*
8452 * Unmute ADC0-2 and set the default input to mic-in
8453 */
8454 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8455 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8456 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8457 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8458 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8459 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8460
Takashi Iwaicb53c622007-08-10 17:21:45 +02008461 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008462 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008463 * Note: PASD motherboards uses the Line In 2 as the input for
8464 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008465 */
8466 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008467 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8468 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8469 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8470 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8471 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008472
8473 /*
8474 * Set up output mixers (0x0c - 0x0e)
8475 */
8476 /* set vol=0 to output mixers */
8477 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8478 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8479 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8480 /* set up input amps for analog loopback */
8481 /* Amp Indices: DAC = 0, mixer = 1 */
8482 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8483 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8484 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8485 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8486 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8487 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8488
8489 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8490 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8491 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8492 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8493 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8494 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8495
8496 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8497 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8498 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8499 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8500 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8501
8502 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8503 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8504
8505 /* FIXME: use matrix-type input source selection */
8506 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8507 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8508 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8509 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8510 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8511 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8512 /* Input mixer2 */
8513 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8514 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8515 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8516 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8517 /* Input mixer3 */
8518 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8519 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8520 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008521 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008522
8523 { }
8524};
8525
Kailang Yangccc656c2006-10-17 12:32:26 +02008526static struct hda_verb alc262_hippo_unsol_verbs[] = {
8527 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8528 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8529 {}
8530};
8531
8532static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8533 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8534 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8535 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8536
8537 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8538 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8539 {}
8540};
8541
Kailang Yang272a5272007-05-14 11:00:38 +02008542static struct hda_verb alc262_sony_unsol_verbs[] = {
8543 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8544 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8545 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8546
8547 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8548 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8549};
8550
Kailang Yangccc656c2006-10-17 12:32:26 +02008551/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008552static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008553{
8554 struct alc_spec *spec = codec->spec;
8555 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008556 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008557
Takashi Iwai5b319542007-07-26 11:49:22 +02008558 /* need to execute and sync at first */
8559 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8560 present = snd_hda_codec_read(codec, 0x15, 0,
8561 AC_VERB_GET_PIN_SENSE, 0);
8562 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008563 if (spec->jack_present) {
8564 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008565 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8566 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008567 } else {
8568 /* unmute internal speaker if necessary */
8569 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008570 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8571 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008572 }
8573}
8574
8575/* unsolicited event for HP jack sensing */
8576static void alc262_hippo_unsol_event(struct hda_codec *codec,
8577 unsigned int res)
8578{
8579 if ((res >> 26) != ALC880_HP_EVENT)
8580 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008581 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008582}
8583
Takashi Iwai5b319542007-07-26 11:49:22 +02008584static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008585{
Kailang Yangccc656c2006-10-17 12:32:26 +02008586 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008587 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008588
Takashi Iwai5b319542007-07-26 11:49:22 +02008589 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8590 present = snd_hda_codec_read(codec, 0x1b, 0,
8591 AC_VERB_GET_PIN_SENSE, 0);
8592 present = (present & 0x80000000) != 0;
8593 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008594 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008595 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8596 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008597 } else {
8598 /* unmute internal speaker if necessary */
8599 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008600 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8601 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008602 }
8603}
8604
8605/* unsolicited event for HP jack sensing */
8606static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8607 unsigned int res)
8608{
8609 if ((res >> 26) != ALC880_HP_EVENT)
8610 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008611 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008612}
8613
Takashi Iwai834be882006-03-01 14:16:17 +01008614/*
8615 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01008616 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
8617 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01008618 */
8619
8620#define ALC_HP_EVENT 0x37
8621
8622static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8623 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8624 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01008625 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8626 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01008627 {}
8628};
8629
Jiang zhe0e31daf2008-03-20 12:12:39 +01008630static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
8631 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8632 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8633 {}
8634};
8635
Takashi Iwai834be882006-03-01 14:16:17 +01008636static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008637 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008638 .items = {
8639 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008640 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008641 { "CD", 0x4 },
8642 },
8643};
8644
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008645static struct hda_input_mux alc262_HP_capture_source = {
8646 .num_items = 5,
8647 .items = {
8648 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008649 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008650 { "Line", 0x2 },
8651 { "CD", 0x4 },
8652 { "AUX IN", 0x6 },
8653 },
8654};
8655
zhejiangaccbe492007-08-31 12:36:05 +02008656static struct hda_input_mux alc262_HP_D7000_capture_source = {
8657 .num_items = 4,
8658 .items = {
8659 { "Mic", 0x0 },
8660 { "Front Mic", 0x2 },
8661 { "Line", 0x1 },
8662 { "CD", 0x4 },
8663 },
8664};
8665
Takashi Iwai834be882006-03-01 14:16:17 +01008666/* mute/unmute internal speaker according to the hp jack and mute state */
8667static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8668{
8669 struct alc_spec *spec = codec->spec;
8670 unsigned int mute;
8671
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008672 if (force || !spec->sense_updated) {
Tony Vroon5d9fab22008-03-14 17:09:18 +01008673 unsigned int present_int_hp, present_dock_hp;
Takashi Iwai834be882006-03-01 14:16:17 +01008674 /* need to execute and sync at first */
8675 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Tony Vroon5d9fab22008-03-14 17:09:18 +01008676 present_int_hp = snd_hda_codec_read(codec, 0x14, 0,
8677 AC_VERB_GET_PIN_SENSE, 0);
8678 snd_hda_codec_read(codec, 0x1B, 0, AC_VERB_SET_PIN_SENSE, 0);
8679 present_dock_hp = snd_hda_codec_read(codec, 0x1b, 0,
8680 AC_VERB_GET_PIN_SENSE, 0);
8681 spec->jack_present = (present_int_hp & 0x80000000) != 0;
8682 spec->jack_present |= (present_dock_hp & 0x80000000) != 0;
Takashi Iwai834be882006-03-01 14:16:17 +01008683 spec->sense_updated = 1;
8684 }
8685 if (spec->jack_present) {
8686 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008687 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8688 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008689 } else {
8690 /* unmute internal speaker if necessary */
8691 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008692 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8693 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008694 }
8695}
8696
8697/* unsolicited event for HP jack sensing */
8698static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8699 unsigned int res)
8700{
8701 if ((res >> 26) != ALC_HP_EVENT)
8702 return;
8703 alc262_fujitsu_automute(codec, 1);
8704}
8705
8706/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008707static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8708 .ops = &snd_hda_bind_vol,
8709 .values = {
8710 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8711 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8712 0
8713 },
8714};
Takashi Iwai834be882006-03-01 14:16:17 +01008715
Jiang zhe0e31daf2008-03-20 12:12:39 +01008716/* mute/unmute internal speaker according to the hp jack and mute state */
8717static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
8718{
8719 struct alc_spec *spec = codec->spec;
8720 unsigned int mute;
8721
8722 if (force || !spec->sense_updated) {
8723 unsigned int present_int_hp;
8724 /* need to execute and sync at first */
8725 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8726 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
8727 AC_VERB_GET_PIN_SENSE, 0);
8728 spec->jack_present = (present_int_hp & 0x80000000) != 0;
8729 spec->sense_updated = 1;
8730 }
8731 if (spec->jack_present) {
8732 /* mute internal speaker */
8733 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8734 HDA_AMP_MUTE, HDA_AMP_MUTE);
8735 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8736 HDA_AMP_MUTE, HDA_AMP_MUTE);
8737 } else {
8738 /* unmute internal speaker if necessary */
8739 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8740 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8741 HDA_AMP_MUTE, mute);
8742 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8743 HDA_AMP_MUTE, mute);
8744 }
8745}
8746
8747/* unsolicited event for HP jack sensing */
8748static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
8749 unsigned int res)
8750{
8751 if ((res >> 26) != ALC_HP_EVENT)
8752 return;
8753 alc262_lenovo_3000_automute(codec, 1);
8754}
8755
Takashi Iwai834be882006-03-01 14:16:17 +01008756/* bind hp and internal speaker mute (with plug check) */
8757static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8758 struct snd_ctl_elem_value *ucontrol)
8759{
8760 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8761 long *valp = ucontrol->value.integer.value;
8762 int change;
8763
Tony Vroon5d9fab22008-03-14 17:09:18 +01008764 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8765 HDA_AMP_MUTE,
8766 valp ? 0 : HDA_AMP_MUTE);
8767 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8768 HDA_AMP_MUTE,
8769 valp ? 0 : HDA_AMP_MUTE);
8770
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008771 if (change)
8772 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008773 return change;
8774}
8775
8776static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008777 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008778 {
8779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8780 .name = "Master Playback Switch",
8781 .info = snd_hda_mixer_amp_switch_info,
8782 .get = snd_hda_mixer_amp_switch_get,
8783 .put = alc262_fujitsu_master_sw_put,
8784 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8785 },
8786 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8787 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02008788 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
8789 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008790 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8791 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8792 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008793 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8794 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8795 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008796 { } /* end */
8797};
8798
Jiang zhe0e31daf2008-03-20 12:12:39 +01008799/* bind hp and internal speaker mute (with plug check) */
8800static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
8801 struct snd_ctl_elem_value *ucontrol)
8802{
8803 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8804 long *valp = ucontrol->value.integer.value;
8805 int change;
8806
8807 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8808 HDA_AMP_MUTE,
8809 valp ? 0 : HDA_AMP_MUTE);
8810
8811 if (change)
8812 alc262_lenovo_3000_automute(codec, 0);
8813 return change;
8814}
8815
8816static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
8817 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
8818 {
8819 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8820 .name = "Master Playback Switch",
8821 .info = snd_hda_mixer_amp_switch_info,
8822 .get = snd_hda_mixer_amp_switch_get,
8823 .put = alc262_lenovo_3000_master_sw_put,
8824 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
8825 },
8826 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8827 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8828 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8829 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8830 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8831 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8832 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8833 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8834 { } /* end */
8835};
8836
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008837/* additional init verbs for Benq laptops */
8838static struct hda_verb alc262_EAPD_verbs[] = {
8839 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8840 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8841 {}
8842};
8843
Kailang Yang83c34212007-07-05 11:43:05 +02008844static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8845 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8846 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8847
8848 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8849 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8850 {}
8851};
8852
Tobin Davisf651b502007-10-26 12:40:47 +02008853/* Samsung Q1 Ultra Vista model setup */
8854static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008855 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8856 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02008857 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8858 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8859 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008860 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02008861 { } /* end */
8862};
8863
8864static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008865 /* output mixer */
8866 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8867 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8868 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8869 /* speaker */
8870 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8871 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8872 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8873 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8874 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02008875 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008876 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8877 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8878 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8879 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8880 /* internal mic */
8881 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8882 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8883 /* ADC, choose mic */
8884 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8885 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8886 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8887 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8888 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8889 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8890 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8891 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
8892 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
8893 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02008894 {}
8895};
8896
Tobin Davisf651b502007-10-26 12:40:47 +02008897/* mute/unmute internal speaker according to the hp jack and mute state */
8898static void alc262_ultra_automute(struct hda_codec *codec)
8899{
8900 struct alc_spec *spec = codec->spec;
8901 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02008902
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008903 mute = 0;
8904 /* auto-mute only when HP is used as HP */
8905 if (!spec->cur_mux[0]) {
8906 unsigned int present;
8907 /* need to execute and sync at first */
8908 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8909 present = snd_hda_codec_read(codec, 0x15, 0,
8910 AC_VERB_GET_PIN_SENSE, 0);
8911 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
8912 if (spec->jack_present)
8913 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02008914 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008915 /* mute/unmute internal speaker */
8916 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8917 HDA_AMP_MUTE, mute);
8918 /* mute/unmute HP */
8919 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8920 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02008921}
8922
8923/* unsolicited event for HP jack sensing */
8924static void alc262_ultra_unsol_event(struct hda_codec *codec,
8925 unsigned int res)
8926{
8927 if ((res >> 26) != ALC880_HP_EVENT)
8928 return;
8929 alc262_ultra_automute(codec);
8930}
8931
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008932static struct hda_input_mux alc262_ultra_capture_source = {
8933 .num_items = 2,
8934 .items = {
8935 { "Mic", 0x1 },
8936 { "Headphone", 0x7 },
8937 },
8938};
8939
8940static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
8941 struct snd_ctl_elem_value *ucontrol)
8942{
8943 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8944 struct alc_spec *spec = codec->spec;
8945 int ret;
8946
8947 ret = alc882_mux_enum_put(kcontrol, ucontrol);
8948 if (!ret)
8949 return 0;
8950 /* reprogram the HP pin as mic or HP according to the input source */
8951 snd_hda_codec_write_cache(codec, 0x15, 0,
8952 AC_VERB_SET_PIN_WIDGET_CONTROL,
8953 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
8954 alc262_ultra_automute(codec); /* mute/unmute HP */
8955 return ret;
8956}
8957
8958static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
8959 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
8960 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
8961 {
8962 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8963 .name = "Capture Source",
8964 .info = alc882_mux_enum_info,
8965 .get = alc882_mux_enum_get,
8966 .put = alc262_ultra_mux_enum_put,
8967 },
8968 { } /* end */
8969};
8970
Kailang Yangdf694da2005-12-05 19:42:22 +01008971/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008972static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
8973 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01008974{
8975 hda_nid_t nid;
8976 int err;
8977
8978 spec->multiout.num_dacs = 1; /* only use one dac */
8979 spec->multiout.dac_nids = spec->private_dac_nids;
8980 spec->multiout.dac_nids[0] = 2;
8981
8982 nid = cfg->line_out_pins[0];
8983 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008984 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8985 "Front Playback Volume",
8986 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
8987 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008988 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008989 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8990 "Front Playback Switch",
8991 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
8992 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008993 return err;
8994 }
8995
Takashi Iwai82bc9552006-03-21 11:24:42 +01008996 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008997 if (nid) {
8998 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008999 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9000 "Speaker Playback Volume",
9001 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9002 HDA_OUTPUT));
9003 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009004 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009005 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9006 "Speaker Playback Switch",
9007 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9008 HDA_OUTPUT));
9009 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009010 return err;
9011 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009012 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9013 "Speaker Playback Switch",
9014 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9015 HDA_OUTPUT));
9016 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009017 return err;
9018 }
9019 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009020 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009021 if (nid) {
9022 /* spec->multiout.hp_nid = 2; */
9023 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009024 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9025 "Headphone Playback Volume",
9026 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9027 HDA_OUTPUT));
9028 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009029 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009030 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9031 "Headphone Playback Switch",
9032 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9033 HDA_OUTPUT));
9034 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009035 return err;
9036 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009037 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9038 "Headphone Playback Switch",
9039 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9040 HDA_OUTPUT));
9041 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009042 return err;
9043 }
9044 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009045 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009046}
9047
9048/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009049#define alc262_auto_create_analog_input_ctls \
9050 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009051
9052/*
9053 * generic initialization of ADC, input mixers and output mixers
9054 */
9055static struct hda_verb alc262_volume_init_verbs[] = {
9056 /*
9057 * Unmute ADC0-2 and set the default input to mic-in
9058 */
9059 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9060 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9061 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9062 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9063 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9064 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9065
Takashi Iwaicb53c622007-08-10 17:21:45 +02009066 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009067 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009068 * Note: PASD motherboards uses the Line In 2 as the input for
9069 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009070 */
9071 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009072 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9073 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9074 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9075 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9076 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009077
9078 /*
9079 * Set up output mixers (0x0c - 0x0f)
9080 */
9081 /* set vol=0 to output mixers */
9082 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9083 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9084 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9085
9086 /* set up input amps for analog loopback */
9087 /* Amp Indices: DAC = 0, mixer = 1 */
9088 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9089 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9090 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9091 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9092 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9093 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9094
9095 /* FIXME: use matrix-type input source selection */
9096 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9097 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9098 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9099 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9100 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9101 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9102 /* Input mixer2 */
9103 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9104 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9105 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9106 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9107 /* Input mixer3 */
9108 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9109 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9110 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9111 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9112
9113 { }
9114};
9115
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009116static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9117 /*
9118 * Unmute ADC0-2 and set the default input to mic-in
9119 */
9120 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9121 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9122 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9123 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9124 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9125 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9126
Takashi Iwaicb53c622007-08-10 17:21:45 +02009127 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009128 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009129 * Note: PASD motherboards uses the Line In 2 as the input for
9130 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009131 */
9132 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009133 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9134 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9135 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9136 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9137 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9138 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9139 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009140
9141 /*
9142 * Set up output mixers (0x0c - 0x0e)
9143 */
9144 /* set vol=0 to output mixers */
9145 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9146 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9147 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9148
9149 /* set up input amps for analog loopback */
9150 /* Amp Indices: DAC = 0, mixer = 1 */
9151 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9152 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9153 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9154 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9155 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9156 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9157
Takashi Iwaice875f02008-01-28 18:17:43 +01009158 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009159 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9160 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9161
9162 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9163 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9164
9165 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9166 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9167
9168 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9169 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9170 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9171 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9172 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9173
9174 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9175 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9176 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9177 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9178 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9179 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9180
9181
9182 /* FIXME: use matrix-type input source selection */
9183 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9184 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9185 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9186 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9187 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9188 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9189 /* Input mixer2 */
9190 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9191 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9192 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9193 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9194 /* Input mixer3 */
9195 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9196 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9197 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9198 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9199
Takashi Iwaice875f02008-01-28 18:17:43 +01009200 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9201
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009202 { }
9203};
9204
Kailang Yangcd7509a2007-01-26 18:33:17 +01009205static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
9206 /*
9207 * Unmute ADC0-2 and set the default input to mic-in
9208 */
9209 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9210 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9211 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9212 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9213 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9214 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9215
Takashi Iwaicb53c622007-08-10 17:21:45 +02009216 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01009217 * mixer widget
9218 * Note: PASD motherboards uses the Line In 2 as the input for front
9219 * panel mic (mic 2)
9220 */
9221 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009222 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9223 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9224 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9225 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9226 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9227 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9228 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9229 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01009230 /*
9231 * Set up output mixers (0x0c - 0x0e)
9232 */
9233 /* set vol=0 to output mixers */
9234 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9235 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9236 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9237
9238 /* set up input amps for analog loopback */
9239 /* Amp Indices: DAC = 0, mixer = 1 */
9240 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9241 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9242 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9243 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9244 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9245 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9246
9247
9248 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
9249 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
9250 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
9251 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
9252 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
9253 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
9254 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
9255
9256 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9257 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9258
9259 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9260 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9261
9262 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
9263 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9264 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9265 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9266 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9267 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9268
9269 /* FIXME: use matrix-type input source selection */
9270 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9271 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9272 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
9273 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
9274 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
9275 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
9276 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
9277 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9278 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
9279 /* Input mixer2 */
9280 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9281 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9282 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9283 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9284 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9285 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9286 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9287 /* Input mixer3 */
9288 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9289 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9290 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9291 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9292 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9293 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9294 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9295
Takashi Iwaice875f02008-01-28 18:17:43 +01009296 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9297
Kailang Yangcd7509a2007-01-26 18:33:17 +01009298 { }
9299};
9300
Takashi Iwaicb53c622007-08-10 17:21:45 +02009301#ifdef CONFIG_SND_HDA_POWER_SAVE
9302#define alc262_loopbacks alc880_loopbacks
9303#endif
9304
Kailang Yangdf694da2005-12-05 19:42:22 +01009305/* pcm configuration: identiacal with ALC880 */
9306#define alc262_pcm_analog_playback alc880_pcm_analog_playback
9307#define alc262_pcm_analog_capture alc880_pcm_analog_capture
9308#define alc262_pcm_digital_playback alc880_pcm_digital_playback
9309#define alc262_pcm_digital_capture alc880_pcm_digital_capture
9310
9311/*
9312 * BIOS auto configuration
9313 */
9314static int alc262_parse_auto_config(struct hda_codec *codec)
9315{
9316 struct alc_spec *spec = codec->spec;
9317 int err;
9318 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
9319
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009320 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9321 alc262_ignore);
9322 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009323 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009324 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01009325 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009326 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
9327 if (err < 0)
9328 return err;
9329 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
9330 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009331 return err;
9332
9333 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9334
9335 if (spec->autocfg.dig_out_pin)
9336 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
9337 if (spec->autocfg.dig_in_pin)
9338 spec->dig_in_nid = ALC262_DIGIN_NID;
9339
9340 if (spec->kctl_alloc)
9341 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9342
9343 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02009344 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01009345 spec->input_mux = &spec->private_imux;
9346
Takashi Iwai776e1842007-08-29 15:07:11 +02009347 err = alc_auto_add_mic_boost(codec);
9348 if (err < 0)
9349 return err;
9350
Kailang Yangdf694da2005-12-05 19:42:22 +01009351 return 1;
9352}
9353
9354#define alc262_auto_init_multi_out alc882_auto_init_multi_out
9355#define alc262_auto_init_hp_out alc882_auto_init_hp_out
9356#define alc262_auto_init_analog_input alc882_auto_init_analog_input
9357
9358
9359/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009360static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01009361{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009362 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01009363 alc262_auto_init_multi_out(codec);
9364 alc262_auto_init_hp_out(codec);
9365 alc262_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009366 if (spec->unsol_event)
9367 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01009368}
9369
9370/*
9371 * configuration and preset
9372 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009373static const char *alc262_models[ALC262_MODEL_LAST] = {
9374 [ALC262_BASIC] = "basic",
9375 [ALC262_HIPPO] = "hippo",
9376 [ALC262_HIPPO_1] = "hippo_1",
9377 [ALC262_FUJITSU] = "fujitsu",
9378 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01009379 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01009380 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +01009381 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009382 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02009383 [ALC262_BENQ_T31] = "benq-t31",
9384 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02009385 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +01009386 [ALC262_LENOVO_3000] = "lenovo-3000",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009387 [ALC262_AUTO] = "auto",
9388};
9389
9390static struct snd_pci_quirk alc262_cfg_tbl[] = {
9391 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
9392 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009393 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009394 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
9395 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009396 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009397 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009398 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009399 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009400 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009401 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009402 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009403 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009404 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009405 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009406 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009407 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009408 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
9409 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
9410 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009411 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
9412 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +01009413 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009414 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009415 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009416 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9417 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9418 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009419 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +01009420 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009421 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009422 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +01009423 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009424 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02009425 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009426 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01009427 {}
9428};
9429
9430static struct alc_config_preset alc262_presets[] = {
9431 [ALC262_BASIC] = {
9432 .mixers = { alc262_base_mixer },
9433 .init_verbs = { alc262_init_verbs },
9434 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9435 .dac_nids = alc262_dac_nids,
9436 .hp_nid = 0x03,
9437 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9438 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01009439 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01009440 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009441 [ALC262_HIPPO] = {
9442 .mixers = { alc262_base_mixer },
9443 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
9444 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9445 .dac_nids = alc262_dac_nids,
9446 .hp_nid = 0x03,
9447 .dig_out_nid = ALC262_DIGOUT_NID,
9448 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9449 .channel_mode = alc262_modes,
9450 .input_mux = &alc262_capture_source,
9451 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009452 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009453 },
9454 [ALC262_HIPPO_1] = {
9455 .mixers = { alc262_hippo1_mixer },
9456 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
9457 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9458 .dac_nids = alc262_dac_nids,
9459 .hp_nid = 0x02,
9460 .dig_out_nid = ALC262_DIGOUT_NID,
9461 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9462 .channel_mode = alc262_modes,
9463 .input_mux = &alc262_capture_source,
9464 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009465 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009466 },
Takashi Iwai834be882006-03-01 14:16:17 +01009467 [ALC262_FUJITSU] = {
9468 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009469 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9470 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01009471 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9472 .dac_nids = alc262_dac_nids,
9473 .hp_nid = 0x03,
9474 .dig_out_nid = ALC262_DIGOUT_NID,
9475 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9476 .channel_mode = alc262_modes,
9477 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009478 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwai834be882006-03-01 14:16:17 +01009479 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009480 [ALC262_HP_BPC] = {
9481 .mixers = { alc262_HP_BPC_mixer },
9482 .init_verbs = { alc262_HP_BPC_init_verbs },
9483 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9484 .dac_nids = alc262_dac_nids,
9485 .hp_nid = 0x03,
9486 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9487 .channel_mode = alc262_modes,
9488 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009489 .unsol_event = alc262_hp_bpc_unsol_event,
9490 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009491 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009492 [ALC262_HP_BPC_D7000_WF] = {
9493 .mixers = { alc262_HP_BPC_WildWest_mixer },
9494 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9495 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9496 .dac_nids = alc262_dac_nids,
9497 .hp_nid = 0x03,
9498 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9499 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009500 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009501 .unsol_event = alc262_hp_wildwest_unsol_event,
9502 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009503 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009504 [ALC262_HP_BPC_D7000_WL] = {
9505 .mixers = { alc262_HP_BPC_WildWest_mixer,
9506 alc262_HP_BPC_WildWest_option_mixer },
9507 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9508 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9509 .dac_nids = alc262_dac_nids,
9510 .hp_nid = 0x03,
9511 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9512 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009513 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009514 .unsol_event = alc262_hp_wildwest_unsol_event,
9515 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009516 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009517 [ALC262_HP_TC_T5735] = {
9518 .mixers = { alc262_hp_t5735_mixer },
9519 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
9520 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9521 .dac_nids = alc262_dac_nids,
9522 .hp_nid = 0x03,
9523 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9524 .channel_mode = alc262_modes,
9525 .input_mux = &alc262_capture_source,
9526 .unsol_event = alc262_hp_t5735_unsol_event,
9527 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +01009528 },
9529 [ALC262_HP_RP5700] = {
9530 .mixers = { alc262_hp_rp5700_mixer },
9531 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
9532 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9533 .dac_nids = alc262_dac_nids,
9534 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9535 .channel_mode = alc262_modes,
9536 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009537 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009538 [ALC262_BENQ_ED8] = {
9539 .mixers = { alc262_base_mixer },
9540 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
9541 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9542 .dac_nids = alc262_dac_nids,
9543 .hp_nid = 0x03,
9544 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9545 .channel_mode = alc262_modes,
9546 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009547 },
Kailang Yang272a5272007-05-14 11:00:38 +02009548 [ALC262_SONY_ASSAMD] = {
9549 .mixers = { alc262_sony_mixer },
9550 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
9551 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9552 .dac_nids = alc262_dac_nids,
9553 .hp_nid = 0x02,
9554 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9555 .channel_mode = alc262_modes,
9556 .input_mux = &alc262_capture_source,
9557 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009558 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02009559 },
9560 [ALC262_BENQ_T31] = {
9561 .mixers = { alc262_benq_t31_mixer },
9562 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
9563 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9564 .dac_nids = alc262_dac_nids,
9565 .hp_nid = 0x03,
9566 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9567 .channel_mode = alc262_modes,
9568 .input_mux = &alc262_capture_source,
9569 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009570 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02009571 },
Tobin Davisf651b502007-10-26 12:40:47 +02009572 [ALC262_ULTRA] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009573 .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
9574 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +02009575 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9576 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +02009577 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9578 .channel_mode = alc262_modes,
9579 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009580 .adc_nids = alc262_adc_nids, /* ADC0 */
9581 .capsrc_nids = alc262_capsrc_nids,
9582 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +02009583 .unsol_event = alc262_ultra_unsol_event,
9584 .init_hook = alc262_ultra_automute,
9585 },
Jiang zhe0e31daf2008-03-20 12:12:39 +01009586 [ALC262_LENOVO_3000] = {
9587 .mixers = { alc262_lenovo_3000_mixer },
9588 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9589 alc262_lenovo_3000_unsol_verbs },
9590 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9591 .dac_nids = alc262_dac_nids,
9592 .hp_nid = 0x03,
9593 .dig_out_nid = ALC262_DIGOUT_NID,
9594 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9595 .channel_mode = alc262_modes,
9596 .input_mux = &alc262_fujitsu_capture_source,
9597 .unsol_event = alc262_lenovo_3000_unsol_event,
9598 },
Kailang Yangdf694da2005-12-05 19:42:22 +01009599};
9600
9601static int patch_alc262(struct hda_codec *codec)
9602{
9603 struct alc_spec *spec;
9604 int board_config;
9605 int err;
9606
Robert P. J. Daydc041e02006-12-19 14:44:15 +01009607 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01009608 if (spec == NULL)
9609 return -ENOMEM;
9610
9611 codec->spec = spec;
9612#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009613 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
9614 * under-run
9615 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009616 {
9617 int tmp;
9618 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9619 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
9620 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9621 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9622 }
9623#endif
9624
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009625 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9626 alc262_models,
9627 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009628
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009629 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009630 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9631 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009632 board_config = ALC262_AUTO;
9633 }
9634
9635 if (board_config == ALC262_AUTO) {
9636 /* automatic parse from the BIOS config */
9637 err = alc262_parse_auto_config(codec);
9638 if (err < 0) {
9639 alc_free(codec);
9640 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009641 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009642 printk(KERN_INFO
9643 "hda_codec: Cannot set up configuration "
9644 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009645 board_config = ALC262_BASIC;
9646 }
9647 }
9648
9649 if (board_config != ALC262_AUTO)
9650 setup_preset(spec, &alc262_presets[board_config]);
9651
9652 spec->stream_name_analog = "ALC262 Analog";
9653 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9654 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9655
9656 spec->stream_name_digital = "ALC262 Digital";
9657 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9658 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9659
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009660 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009661 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009662 unsigned int wcap = get_wcaps(codec, 0x07);
9663
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009664 /* get type */
9665 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009666 if (wcap != AC_WID_AUD_IN) {
9667 spec->adc_nids = alc262_adc_nids_alt;
9668 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +01009669 spec->capsrc_nids = alc262_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009670 spec->mixers[spec->num_mixers] =
9671 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009672 spec->num_mixers++;
9673 } else {
9674 spec->adc_nids = alc262_adc_nids;
9675 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +01009676 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01009677 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9678 spec->num_mixers++;
9679 }
9680 }
9681
Takashi Iwai2134ea42008-01-10 16:53:55 +01009682 spec->vmaster_nid = 0x0c;
9683
Kailang Yangdf694da2005-12-05 19:42:22 +01009684 codec->patch_ops = alc_patch_ops;
9685 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009686 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009687#ifdef CONFIG_SND_HDA_POWER_SAVE
9688 if (!spec->loopback.amplist)
9689 spec->loopback.amplist = alc262_loopbacks;
9690#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009691
Kailang Yangdf694da2005-12-05 19:42:22 +01009692 return 0;
9693}
9694
Kailang Yangdf694da2005-12-05 19:42:22 +01009695/*
Kailang Yanga361d842007-06-05 12:30:55 +02009696 * ALC268 channel source setting (2 channel)
9697 */
9698#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9699#define alc268_modes alc260_modes
9700
9701static hda_nid_t alc268_dac_nids[2] = {
9702 /* front, hp */
9703 0x02, 0x03
9704};
9705
9706static hda_nid_t alc268_adc_nids[2] = {
9707 /* ADC0-1 */
9708 0x08, 0x07
9709};
9710
9711static hda_nid_t alc268_adc_nids_alt[1] = {
9712 /* ADC0 */
9713 0x08
9714};
9715
Takashi Iwaie1406342008-02-11 18:32:32 +01009716static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
9717
Kailang Yanga361d842007-06-05 12:30:55 +02009718static struct snd_kcontrol_new alc268_base_mixer[] = {
9719 /* output mixer control */
9720 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9721 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9722 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9723 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009724 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9725 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9726 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009727 { }
9728};
9729
Takashi Iwaiaef9d312008-02-19 13:16:41 +01009730/* bind Beep switches of both NID 0x0f and 0x10 */
9731static struct hda_bind_ctls alc268_bind_beep_sw = {
9732 .ops = &snd_hda_bind_sw,
9733 .values = {
9734 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
9735 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
9736 0
9737 },
9738};
9739
9740static struct snd_kcontrol_new alc268_beep_mixer[] = {
9741 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
9742 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
9743 { }
9744};
9745
Kailang Yangd1a991a2007-08-15 16:21:59 +02009746static struct hda_verb alc268_eapd_verbs[] = {
9747 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9748 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9749 { }
9750};
9751
Takashi Iwaid2738092007-08-16 14:59:45 +02009752/* Toshiba specific */
9753#define alc268_toshiba_automute alc262_hippo_automute
9754
9755static struct hda_verb alc268_toshiba_verbs[] = {
9756 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9757 { } /* end */
9758};
9759
9760/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009761/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009762static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9763 .ops = &snd_hda_bind_vol,
9764 .values = {
9765 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9766 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9767 0
9768 },
9769};
9770
Takashi Iwai889c4392007-08-23 18:56:52 +02009771/* mute/unmute internal speaker according to the hp jack and mute state */
9772static void alc268_acer_automute(struct hda_codec *codec, int force)
9773{
9774 struct alc_spec *spec = codec->spec;
9775 unsigned int mute;
9776
9777 if (force || !spec->sense_updated) {
9778 unsigned int present;
9779 present = snd_hda_codec_read(codec, 0x14, 0,
9780 AC_VERB_GET_PIN_SENSE, 0);
9781 spec->jack_present = (present & 0x80000000) != 0;
9782 spec->sense_updated = 1;
9783 }
9784 if (spec->jack_present)
9785 mute = HDA_AMP_MUTE; /* mute internal speaker */
9786 else /* unmute internal speaker if necessary */
9787 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9788 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9789 HDA_AMP_MUTE, mute);
9790}
9791
9792
9793/* bind hp and internal speaker mute (with plug check) */
9794static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9795 struct snd_ctl_elem_value *ucontrol)
9796{
9797 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9798 long *valp = ucontrol->value.integer.value;
9799 int change;
9800
9801 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9802 HDA_AMP_MUTE,
9803 valp[0] ? 0 : HDA_AMP_MUTE);
9804 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9805 HDA_AMP_MUTE,
9806 valp[1] ? 0 : HDA_AMP_MUTE);
9807 if (change)
9808 alc268_acer_automute(codec, 0);
9809 return change;
9810}
Takashi Iwaid2738092007-08-16 14:59:45 +02009811
9812static struct snd_kcontrol_new alc268_acer_mixer[] = {
9813 /* output mixer control */
9814 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9815 {
9816 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9817 .name = "Master Playback Switch",
9818 .info = snd_hda_mixer_amp_switch_info,
9819 .get = snd_hda_mixer_amp_switch_get,
9820 .put = alc268_acer_master_sw_put,
9821 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9822 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009823 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9824 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9825 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009826 { }
9827};
9828
9829static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +01009830 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
9831 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +02009832 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9833 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +01009834 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9835 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +02009836
9837 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9838 { }
9839};
9840
9841/* unsolicited event for HP jack sensing */
9842static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9843 unsigned int res)
9844{
Takashi Iwai889c4392007-08-23 18:56:52 +02009845 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009846 return;
9847 alc268_toshiba_automute(codec);
9848}
9849
9850static void alc268_acer_unsol_event(struct hda_codec *codec,
9851 unsigned int res)
9852{
Takashi Iwai889c4392007-08-23 18:56:52 +02009853 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009854 return;
9855 alc268_acer_automute(codec, 1);
9856}
9857
Takashi Iwai889c4392007-08-23 18:56:52 +02009858static void alc268_acer_init_hook(struct hda_codec *codec)
9859{
9860 alc268_acer_automute(codec, 1);
9861}
9862
Takashi Iwai3866f0b2008-01-15 12:37:42 +01009863static struct snd_kcontrol_new alc268_dell_mixer[] = {
9864 /* output mixer control */
9865 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9866 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9867 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9868 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9869 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9870 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9871 { }
9872};
9873
9874static struct hda_verb alc268_dell_verbs[] = {
9875 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9876 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9877 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9878 { }
9879};
9880
9881/* mute/unmute internal speaker according to the hp jack and mute state */
9882static void alc268_dell_automute(struct hda_codec *codec)
9883{
9884 unsigned int present;
9885 unsigned int mute;
9886
9887 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
9888 if (present & 0x80000000)
9889 mute = HDA_AMP_MUTE;
9890 else
9891 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
9892 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9893 HDA_AMP_MUTE, mute);
9894}
9895
9896static void alc268_dell_unsol_event(struct hda_codec *codec,
9897 unsigned int res)
9898{
9899 if ((res >> 26) != ALC880_HP_EVENT)
9900 return;
9901 alc268_dell_automute(codec);
9902}
9903
9904#define alc268_dell_init_hook alc268_dell_automute
9905
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +02009906static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
9907 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9908 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9909 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9910 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9911 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9912 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
9913 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
9914 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9915 { }
9916};
9917
9918static struct hda_verb alc267_quanta_il1_verbs[] = {
9919 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9920 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9921 { }
9922};
9923
9924static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
9925{
9926 unsigned int present;
9927
9928 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
9929 & AC_PINSENSE_PRESENCE;
9930 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
9931 present ? 0 : PIN_OUT);
9932}
9933
9934static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
9935{
9936 unsigned int present;
9937
9938 present = snd_hda_codec_read(codec, 0x18, 0,
9939 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9940 snd_hda_codec_write(codec, 0x23, 0,
9941 AC_VERB_SET_CONNECT_SEL,
9942 present ? 0x00 : 0x01);
9943}
9944
9945static void alc267_quanta_il1_automute(struct hda_codec *codec)
9946{
9947 alc267_quanta_il1_hp_automute(codec);
9948 alc267_quanta_il1_mic_automute(codec);
9949}
9950
9951static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
9952 unsigned int res)
9953{
9954 switch (res >> 26) {
9955 case ALC880_HP_EVENT:
9956 alc267_quanta_il1_hp_automute(codec);
9957 break;
9958 case ALC880_MIC_EVENT:
9959 alc267_quanta_il1_mic_automute(codec);
9960 break;
9961 }
9962}
9963
Kailang Yanga361d842007-06-05 12:30:55 +02009964/*
9965 * generic initialization of ADC, input mixers and output mixers
9966 */
9967static struct hda_verb alc268_base_init_verbs[] = {
9968 /* Unmute DAC0-1 and set vol = 0 */
9969 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9970 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9971 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9972 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9973 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9974 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9975
9976 /*
9977 * Set up output mixers (0x0c - 0x0e)
9978 */
9979 /* set vol=0 to output mixers */
9980 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9981 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9982 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9983 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
9984
9985 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9986 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9987
9988 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9989 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9990 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9991 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9992 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9993 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9994 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9995 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9996
9997 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9998 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9999 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10000 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10001 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10002 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10003 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010004
10005 /* set PCBEEP vol = 0, mute connections */
10006 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10007 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10008 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010009
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010010 /* Unmute Selector 23h,24h and set the default input to mic-in */
10011
10012 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10013 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10014 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
10015 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020010016
Kailang Yanga361d842007-06-05 12:30:55 +020010017 { }
10018};
10019
10020/*
10021 * generic initialization of ADC, input mixers and output mixers
10022 */
10023static struct hda_verb alc268_volume_init_verbs[] = {
10024 /* set output DAC */
10025 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10026 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10027 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10028 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10029
10030 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10031 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10032 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10033 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10034 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10035
10036 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10037 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10038 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10039 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10040 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10041
10042 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10043 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10044 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10045 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10046
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010047 /* set PCBEEP vol = 0, mute connections */
10048 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10049 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10050 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010051
10052 { }
10053};
10054
10055#define alc268_mux_enum_info alc_mux_enum_info
10056#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010010057#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +020010058
10059static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
10060 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10061 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
10062 {
10063 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10064 /* The multiple "Capture Source" controls confuse alsamixer
10065 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020010066 */
10067 /* .name = "Capture Source", */
10068 .name = "Input Source",
10069 .count = 1,
10070 .info = alc268_mux_enum_info,
10071 .get = alc268_mux_enum_get,
10072 .put = alc268_mux_enum_put,
10073 },
10074 { } /* end */
10075};
10076
10077static struct snd_kcontrol_new alc268_capture_mixer[] = {
10078 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10079 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
10080 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
10081 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
10082 {
10083 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10084 /* The multiple "Capture Source" controls confuse alsamixer
10085 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020010086 */
10087 /* .name = "Capture Source", */
10088 .name = "Input Source",
10089 .count = 2,
10090 .info = alc268_mux_enum_info,
10091 .get = alc268_mux_enum_get,
10092 .put = alc268_mux_enum_put,
10093 },
10094 { } /* end */
10095};
10096
10097static struct hda_input_mux alc268_capture_source = {
10098 .num_items = 4,
10099 .items = {
10100 { "Mic", 0x0 },
10101 { "Front Mic", 0x1 },
10102 { "Line", 0x2 },
10103 { "CD", 0x3 },
10104 },
10105};
10106
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010107static struct hda_input_mux alc268_acer_capture_source = {
10108 .num_items = 3,
10109 .items = {
10110 { "Mic", 0x0 },
10111 { "Internal Mic", 0x6 },
10112 { "Line", 0x2 },
10113 },
10114};
10115
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010116#ifdef CONFIG_SND_DEBUG
10117static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010118 /* Volume widgets */
10119 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10120 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10121 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
10122 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
10123 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
10124 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
10125 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
10126 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
10127 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
10128 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
10129 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
10130 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
10131 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010010132 /* The below appears problematic on some hardwares */
10133 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010134 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10135 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
10136 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
10137 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
10138
10139 /* Modes for retasking pin widgets */
10140 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
10141 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
10142 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
10143 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
10144
10145 /* Controls for GPIO pins, assuming they are configured as outputs */
10146 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
10147 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
10148 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
10149 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
10150
10151 /* Switches to allow the digital SPDIF output pin to be enabled.
10152 * The ALC268 does not have an SPDIF input.
10153 */
10154 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
10155
10156 /* A switch allowing EAPD to be enabled. Some laptops seem to use
10157 * this output to turn on an external amplifier.
10158 */
10159 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
10160 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
10161
10162 { } /* end */
10163};
10164#endif
10165
Kailang Yanga361d842007-06-05 12:30:55 +020010166/* create input playback/capture controls for the given pin */
10167static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
10168 const char *ctlname, int idx)
10169{
10170 char name[32];
10171 int err;
10172
10173 sprintf(name, "%s Playback Volume", ctlname);
10174 if (nid == 0x14) {
10175 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
10176 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
10177 HDA_OUTPUT));
10178 if (err < 0)
10179 return err;
10180 } else if (nid == 0x15) {
10181 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
10182 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
10183 HDA_OUTPUT));
10184 if (err < 0)
10185 return err;
10186 } else
10187 return -1;
10188 sprintf(name, "%s Playback Switch", ctlname);
10189 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
10190 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
10191 if (err < 0)
10192 return err;
10193 return 0;
10194}
10195
10196/* add playback controls from the parsed DAC table */
10197static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
10198 const struct auto_pin_cfg *cfg)
10199{
10200 hda_nid_t nid;
10201 int err;
10202
10203 spec->multiout.num_dacs = 2; /* only use one dac */
10204 spec->multiout.dac_nids = spec->private_dac_nids;
10205 spec->multiout.dac_nids[0] = 2;
10206 spec->multiout.dac_nids[1] = 3;
10207
10208 nid = cfg->line_out_pins[0];
10209 if (nid)
10210 alc268_new_analog_output(spec, nid, "Front", 0);
10211
10212 nid = cfg->speaker_pins[0];
10213 if (nid == 0x1d) {
10214 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10215 "Speaker Playback Volume",
10216 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10217 if (err < 0)
10218 return err;
10219 }
10220 nid = cfg->hp_pins[0];
10221 if (nid)
10222 alc268_new_analog_output(spec, nid, "Headphone", 0);
10223
10224 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
10225 if (nid == 0x16) {
10226 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10227 "Mono Playback Switch",
10228 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
10229 if (err < 0)
10230 return err;
10231 }
10232 return 0;
10233}
10234
10235/* create playback/capture controls for input pins */
10236static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
10237 const struct auto_pin_cfg *cfg)
10238{
10239 struct hda_input_mux *imux = &spec->private_imux;
10240 int i, idx1;
10241
10242 for (i = 0; i < AUTO_PIN_LAST; i++) {
10243 switch(cfg->input_pins[i]) {
10244 case 0x18:
10245 idx1 = 0; /* Mic 1 */
10246 break;
10247 case 0x19:
10248 idx1 = 1; /* Mic 2 */
10249 break;
10250 case 0x1a:
10251 idx1 = 2; /* Line In */
10252 break;
10253 case 0x1c:
10254 idx1 = 3; /* CD */
10255 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010010256 case 0x12:
10257 case 0x13:
10258 idx1 = 6; /* digital mics */
10259 break;
Kailang Yanga361d842007-06-05 12:30:55 +020010260 default:
10261 continue;
10262 }
10263 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
10264 imux->items[imux->num_items].index = idx1;
10265 imux->num_items++;
10266 }
10267 return 0;
10268}
10269
10270static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
10271{
10272 struct alc_spec *spec = codec->spec;
10273 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10274 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10275 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10276 unsigned int dac_vol1, dac_vol2;
10277
10278 if (speaker_nid) {
10279 snd_hda_codec_write(codec, speaker_nid, 0,
10280 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
10281 snd_hda_codec_write(codec, 0x0f, 0,
10282 AC_VERB_SET_AMP_GAIN_MUTE,
10283 AMP_IN_UNMUTE(1));
10284 snd_hda_codec_write(codec, 0x10, 0,
10285 AC_VERB_SET_AMP_GAIN_MUTE,
10286 AMP_IN_UNMUTE(1));
10287 } else {
10288 snd_hda_codec_write(codec, 0x0f, 0,
10289 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
10290 snd_hda_codec_write(codec, 0x10, 0,
10291 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
10292 }
10293
10294 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
10295 if (line_nid == 0x14)
10296 dac_vol2 = AMP_OUT_ZERO;
10297 else if (line_nid == 0x15)
10298 dac_vol1 = AMP_OUT_ZERO;
10299 if (hp_nid == 0x14)
10300 dac_vol2 = AMP_OUT_ZERO;
10301 else if (hp_nid == 0x15)
10302 dac_vol1 = AMP_OUT_ZERO;
10303 if (line_nid != 0x16 || hp_nid != 0x16 ||
10304 spec->autocfg.line_out_pins[1] != 0x16 ||
10305 spec->autocfg.line_out_pins[2] != 0x16)
10306 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
10307
10308 snd_hda_codec_write(codec, 0x02, 0,
10309 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
10310 snd_hda_codec_write(codec, 0x03, 0,
10311 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
10312}
10313
10314/* pcm configuration: identiacal with ALC880 */
10315#define alc268_pcm_analog_playback alc880_pcm_analog_playback
10316#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010010317#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020010318#define alc268_pcm_digital_playback alc880_pcm_digital_playback
10319
10320/*
10321 * BIOS auto configuration
10322 */
10323static int alc268_parse_auto_config(struct hda_codec *codec)
10324{
10325 struct alc_spec *spec = codec->spec;
10326 int err;
10327 static hda_nid_t alc268_ignore[] = { 0 };
10328
10329 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10330 alc268_ignore);
10331 if (err < 0)
10332 return err;
10333 if (!spec->autocfg.line_outs)
10334 return 0; /* can't find valid BIOS pin config */
10335
10336 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
10337 if (err < 0)
10338 return err;
10339 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
10340 if (err < 0)
10341 return err;
10342
10343 spec->multiout.max_channels = 2;
10344
10345 /* digital only support output */
10346 if (spec->autocfg.dig_out_pin)
10347 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
10348
10349 if (spec->kctl_alloc)
10350 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10351
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010352 if (spec->autocfg.speaker_pins[0] != 0x1d)
10353 spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
10354
Kailang Yanga361d842007-06-05 12:30:55 +020010355 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
10356 spec->num_mux_defs = 1;
10357 spec->input_mux = &spec->private_imux;
10358
Takashi Iwai776e1842007-08-29 15:07:11 +020010359 err = alc_auto_add_mic_boost(codec);
10360 if (err < 0)
10361 return err;
10362
Kailang Yanga361d842007-06-05 12:30:55 +020010363 return 1;
10364}
10365
10366#define alc268_auto_init_multi_out alc882_auto_init_multi_out
10367#define alc268_auto_init_hp_out alc882_auto_init_hp_out
10368#define alc268_auto_init_analog_input alc882_auto_init_analog_input
10369
10370/* init callback for auto-configuration model -- overriding the default init */
10371static void alc268_auto_init(struct hda_codec *codec)
10372{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010373 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020010374 alc268_auto_init_multi_out(codec);
10375 alc268_auto_init_hp_out(codec);
10376 alc268_auto_init_mono_speaker_out(codec);
10377 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010378 if (spec->unsol_event)
10379 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020010380}
10381
10382/*
10383 * configuration and preset
10384 */
10385static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010386 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020010387 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020010388 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020010389 [ALC268_ACER] = "acer",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010390 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010391 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010392#ifdef CONFIG_SND_DEBUG
10393 [ALC268_TEST] = "test",
10394#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010395 [ALC268_AUTO] = "auto",
10396};
10397
10398static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010399 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010010400 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010401 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010010402 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010403 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010404 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020010405 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020010406 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020010407 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020010408 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010409 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010410 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020010411 {}
10412};
10413
10414static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010415 [ALC267_QUANTA_IL1] = {
10416 .mixers = { alc267_quanta_il1_mixer },
10417 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10418 alc267_quanta_il1_verbs },
10419 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10420 .dac_nids = alc268_dac_nids,
10421 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10422 .adc_nids = alc268_adc_nids_alt,
10423 .hp_nid = 0x03,
10424 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10425 .channel_mode = alc268_modes,
10426 .input_mux = &alc268_capture_source,
10427 .unsol_event = alc267_quanta_il1_unsol_event,
10428 .init_hook = alc267_quanta_il1_automute,
10429 },
Kailang Yanga361d842007-06-05 12:30:55 +020010430 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010431 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10432 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020010433 .init_verbs = { alc268_base_init_verbs },
10434 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10435 .dac_nids = alc268_dac_nids,
10436 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10437 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010438 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020010439 .hp_nid = 0x03,
10440 .dig_out_nid = ALC268_DIGOUT_NID,
10441 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10442 .channel_mode = alc268_modes,
10443 .input_mux = &alc268_capture_source,
10444 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010445 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010446 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10447 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010448 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10449 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010450 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10451 .dac_nids = alc268_dac_nids,
10452 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10453 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010454 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010455 .hp_nid = 0x03,
10456 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10457 .channel_mode = alc268_modes,
10458 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010459 .unsol_event = alc268_toshiba_unsol_event,
10460 .init_hook = alc268_toshiba_automute,
10461 },
10462 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010463 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
10464 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010465 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10466 alc268_acer_verbs },
10467 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10468 .dac_nids = alc268_dac_nids,
10469 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10470 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010471 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020010472 .hp_nid = 0x02,
10473 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10474 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010475 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010476 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020010477 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010478 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010479 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010480 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010481 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10482 alc268_dell_verbs },
10483 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10484 .dac_nids = alc268_dac_nids,
10485 .hp_nid = 0x02,
10486 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10487 .channel_mode = alc268_modes,
10488 .unsol_event = alc268_dell_unsol_event,
10489 .init_hook = alc268_dell_init_hook,
10490 .input_mux = &alc268_capture_source,
10491 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010492 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010493 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10494 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010495 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10496 alc268_toshiba_verbs },
10497 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10498 .dac_nids = alc268_dac_nids,
10499 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10500 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010501 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010502 .hp_nid = 0x03,
10503 .dig_out_nid = ALC268_DIGOUT_NID,
10504 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10505 .channel_mode = alc268_modes,
10506 .input_mux = &alc268_capture_source,
10507 .unsol_event = alc268_toshiba_unsol_event,
10508 .init_hook = alc268_toshiba_automute
10509 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010510#ifdef CONFIG_SND_DEBUG
10511 [ALC268_TEST] = {
10512 .mixers = { alc268_test_mixer, alc268_capture_mixer },
10513 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10514 alc268_volume_init_verbs },
10515 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10516 .dac_nids = alc268_dac_nids,
10517 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10518 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010519 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010520 .hp_nid = 0x03,
10521 .dig_out_nid = ALC268_DIGOUT_NID,
10522 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10523 .channel_mode = alc268_modes,
10524 .input_mux = &alc268_capture_source,
10525 },
10526#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010527};
10528
10529static int patch_alc268(struct hda_codec *codec)
10530{
10531 struct alc_spec *spec;
10532 int board_config;
10533 int err;
10534
10535 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
10536 if (spec == NULL)
10537 return -ENOMEM;
10538
10539 codec->spec = spec;
10540
10541 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
10542 alc268_models,
10543 alc268_cfg_tbl);
10544
10545 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
10546 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
10547 "trying auto-probe from BIOS...\n");
10548 board_config = ALC268_AUTO;
10549 }
10550
10551 if (board_config == ALC268_AUTO) {
10552 /* automatic parse from the BIOS config */
10553 err = alc268_parse_auto_config(codec);
10554 if (err < 0) {
10555 alc_free(codec);
10556 return err;
10557 } else if (!err) {
10558 printk(KERN_INFO
10559 "hda_codec: Cannot set up configuration "
10560 "from BIOS. Using base mode...\n");
10561 board_config = ALC268_3ST;
10562 }
10563 }
10564
10565 if (board_config != ALC268_AUTO)
10566 setup_preset(spec, &alc268_presets[board_config]);
10567
10568 spec->stream_name_analog = "ALC268 Analog";
10569 spec->stream_analog_playback = &alc268_pcm_analog_playback;
10570 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010010571 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020010572
10573 spec->stream_name_digital = "ALC268 Digital";
10574 spec->stream_digital_playback = &alc268_pcm_digital_playback;
10575
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010576 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
10577 /* override the amp caps for beep generator */
10578 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
10579 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
10580 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
10581 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
10582 (0 << AC_AMPCAP_MUTE_SHIFT));
10583
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010584 if (!spec->adc_nids && spec->input_mux) {
10585 /* check whether NID 0x07 is valid */
10586 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010010587 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020010588
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010589 /* get type */
10590 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010010591 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010592 spec->adc_nids = alc268_adc_nids_alt;
10593 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
10594 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020010595 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010596 spec->num_mixers++;
10597 } else {
10598 spec->adc_nids = alc268_adc_nids;
10599 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
10600 spec->mixers[spec->num_mixers] =
10601 alc268_capture_mixer;
10602 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020010603 }
Takashi Iwaie1406342008-02-11 18:32:32 +010010604 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010010605 /* set default input source */
10606 for (i = 0; i < spec->num_adc_nids; i++)
10607 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
10608 0, AC_VERB_SET_CONNECT_SEL,
10609 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020010610 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010010611
10612 spec->vmaster_nid = 0x02;
10613
Kailang Yanga361d842007-06-05 12:30:55 +020010614 codec->patch_ops = alc_patch_ops;
10615 if (board_config == ALC268_AUTO)
10616 spec->init_hook = alc268_auto_init;
10617
10618 return 0;
10619}
10620
10621/*
Kailang Yangf6a92242007-12-13 16:52:54 +010010622 * ALC269 channel source setting (2 channel)
10623 */
10624#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
10625
10626#define alc269_dac_nids alc260_dac_nids
10627
10628static hda_nid_t alc269_adc_nids[1] = {
10629 /* ADC1 */
10630 0x07,
10631};
10632
10633#define alc269_modes alc260_modes
10634#define alc269_capture_source alc880_lg_lw_capture_source
10635
10636static struct snd_kcontrol_new alc269_base_mixer[] = {
10637 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10638 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10639 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10640 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10641 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10643 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10644 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10645 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10646 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10647 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10648 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
10649 { } /* end */
10650};
10651
10652/* capture mixer elements */
10653static struct snd_kcontrol_new alc269_capture_mixer[] = {
10654 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10655 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10656 {
10657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10658 /* The multiple "Capture Source" controls confuse alsamixer
10659 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010010660 */
10661 /* .name = "Capture Source", */
10662 .name = "Input Source",
10663 .count = 1,
10664 .info = alc_mux_enum_info,
10665 .get = alc_mux_enum_get,
10666 .put = alc_mux_enum_put,
10667 },
10668 { } /* end */
10669};
10670
10671/*
10672 * generic initialization of ADC, input mixers and output mixers
10673 */
10674static struct hda_verb alc269_init_verbs[] = {
10675 /*
10676 * Unmute ADC0 and set the default input to mic-in
10677 */
10678 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10679
10680 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
10681 * analog-loopback mixer widget
10682 * Note: PASD motherboards uses the Line In 2 as the input for
10683 * front panel mic (mic 2)
10684 */
10685 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
10686 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10687 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10688 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10689 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10690 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10691
10692 /*
10693 * Set up output mixers (0x0c - 0x0e)
10694 */
10695 /* set vol=0 to output mixers */
10696 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10697 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10698
10699 /* set up input amps for analog loopback */
10700 /* Amp Indices: DAC = 0, mixer = 1 */
10701 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10702 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10703 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10704 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10705 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10706 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10707
10708 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10709 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10710 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10711 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10712 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10713 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10714 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10715
10716 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10717 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10718 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10719 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10720 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10721 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10722 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10723
10724 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10725 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10726
10727 /* FIXME: use matrix-type input source selection */
10728 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
10729 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10730 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10731 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10732 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10733 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10734
10735 /* set EAPD */
10736 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10737 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10738 { }
10739};
10740
10741/* add playback controls from the parsed DAC table */
10742static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
10743 const struct auto_pin_cfg *cfg)
10744{
10745 hda_nid_t nid;
10746 int err;
10747
10748 spec->multiout.num_dacs = 1; /* only use one dac */
10749 spec->multiout.dac_nids = spec->private_dac_nids;
10750 spec->multiout.dac_nids[0] = 2;
10751
10752 nid = cfg->line_out_pins[0];
10753 if (nid) {
10754 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10755 "Front Playback Volume",
10756 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
10757 if (err < 0)
10758 return err;
10759 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10760 "Front Playback Switch",
10761 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10762 if (err < 0)
10763 return err;
10764 }
10765
10766 nid = cfg->speaker_pins[0];
10767 if (nid) {
10768 if (!cfg->line_out_pins[0]) {
10769 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10770 "Speaker Playback Volume",
10771 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10772 HDA_OUTPUT));
10773 if (err < 0)
10774 return err;
10775 }
10776 if (nid == 0x16) {
10777 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10778 "Speaker Playback Switch",
10779 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10780 HDA_OUTPUT));
10781 if (err < 0)
10782 return err;
10783 } else {
10784 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10785 "Speaker Playback Switch",
10786 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10787 HDA_OUTPUT));
10788 if (err < 0)
10789 return err;
10790 }
10791 }
10792 nid = cfg->hp_pins[0];
10793 if (nid) {
10794 /* spec->multiout.hp_nid = 2; */
10795 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
10796 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10797 "Headphone Playback Volume",
10798 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10799 HDA_OUTPUT));
10800 if (err < 0)
10801 return err;
10802 }
10803 if (nid == 0x16) {
10804 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10805 "Headphone Playback Switch",
10806 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10807 HDA_OUTPUT));
10808 if (err < 0)
10809 return err;
10810 } else {
10811 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10812 "Headphone Playback Switch",
10813 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10814 HDA_OUTPUT));
10815 if (err < 0)
10816 return err;
10817 }
10818 }
10819 return 0;
10820}
10821
10822#define alc269_auto_create_analog_input_ctls \
10823 alc880_auto_create_analog_input_ctls
10824
10825#ifdef CONFIG_SND_HDA_POWER_SAVE
10826#define alc269_loopbacks alc880_loopbacks
10827#endif
10828
10829/* pcm configuration: identiacal with ALC880 */
10830#define alc269_pcm_analog_playback alc880_pcm_analog_playback
10831#define alc269_pcm_analog_capture alc880_pcm_analog_capture
10832#define alc269_pcm_digital_playback alc880_pcm_digital_playback
10833#define alc269_pcm_digital_capture alc880_pcm_digital_capture
10834
10835/*
10836 * BIOS auto configuration
10837 */
10838static int alc269_parse_auto_config(struct hda_codec *codec)
10839{
10840 struct alc_spec *spec = codec->spec;
10841 int err;
10842 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
10843
10844 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10845 alc269_ignore);
10846 if (err < 0)
10847 return err;
10848
10849 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
10850 if (err < 0)
10851 return err;
10852 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
10853 if (err < 0)
10854 return err;
10855
10856 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10857
10858 if (spec->autocfg.dig_out_pin)
10859 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
10860
10861 if (spec->kctl_alloc)
10862 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10863
10864 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
10865 spec->num_mux_defs = 1;
10866 spec->input_mux = &spec->private_imux;
10867
10868 err = alc_auto_add_mic_boost(codec);
10869 if (err < 0)
10870 return err;
10871
10872 return 1;
10873}
10874
10875#define alc269_auto_init_multi_out alc882_auto_init_multi_out
10876#define alc269_auto_init_hp_out alc882_auto_init_hp_out
10877#define alc269_auto_init_analog_input alc882_auto_init_analog_input
10878
10879
10880/* init callback for auto-configuration model -- overriding the default init */
10881static void alc269_auto_init(struct hda_codec *codec)
10882{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010883 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010010884 alc269_auto_init_multi_out(codec);
10885 alc269_auto_init_hp_out(codec);
10886 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010887 if (spec->unsol_event)
10888 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010010889}
10890
10891/*
10892 * configuration and preset
10893 */
10894static const char *alc269_models[ALC269_MODEL_LAST] = {
10895 [ALC269_BASIC] = "basic",
10896};
10897
10898static struct snd_pci_quirk alc269_cfg_tbl[] = {
10899 {}
10900};
10901
10902static struct alc_config_preset alc269_presets[] = {
10903 [ALC269_BASIC] = {
10904 .mixers = { alc269_base_mixer },
10905 .init_verbs = { alc269_init_verbs },
10906 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
10907 .dac_nids = alc269_dac_nids,
10908 .hp_nid = 0x03,
10909 .num_channel_mode = ARRAY_SIZE(alc269_modes),
10910 .channel_mode = alc269_modes,
10911 .input_mux = &alc269_capture_source,
10912 },
10913};
10914
10915static int patch_alc269(struct hda_codec *codec)
10916{
10917 struct alc_spec *spec;
10918 int board_config;
10919 int err;
10920
10921 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10922 if (spec == NULL)
10923 return -ENOMEM;
10924
10925 codec->spec = spec;
10926
10927 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
10928 alc269_models,
10929 alc269_cfg_tbl);
10930
10931 if (board_config < 0) {
10932 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
10933 "trying auto-probe from BIOS...\n");
10934 board_config = ALC269_AUTO;
10935 }
10936
10937 if (board_config == ALC269_AUTO) {
10938 /* automatic parse from the BIOS config */
10939 err = alc269_parse_auto_config(codec);
10940 if (err < 0) {
10941 alc_free(codec);
10942 return err;
10943 } else if (!err) {
10944 printk(KERN_INFO
10945 "hda_codec: Cannot set up configuration "
10946 "from BIOS. Using base mode...\n");
10947 board_config = ALC269_BASIC;
10948 }
10949 }
10950
10951 if (board_config != ALC269_AUTO)
10952 setup_preset(spec, &alc269_presets[board_config]);
10953
10954 spec->stream_name_analog = "ALC269 Analog";
10955 spec->stream_analog_playback = &alc269_pcm_analog_playback;
10956 spec->stream_analog_capture = &alc269_pcm_analog_capture;
10957
10958 spec->stream_name_digital = "ALC269 Digital";
10959 spec->stream_digital_playback = &alc269_pcm_digital_playback;
10960 spec->stream_digital_capture = &alc269_pcm_digital_capture;
10961
10962 spec->adc_nids = alc269_adc_nids;
10963 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
10964 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
10965 spec->num_mixers++;
10966
10967 codec->patch_ops = alc_patch_ops;
10968 if (board_config == ALC269_AUTO)
10969 spec->init_hook = alc269_auto_init;
10970#ifdef CONFIG_SND_HDA_POWER_SAVE
10971 if (!spec->loopback.amplist)
10972 spec->loopback.amplist = alc269_loopbacks;
10973#endif
10974
10975 return 0;
10976}
10977
10978/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010979 * ALC861 channel source setting (2/6 channel selection for 3-stack)
10980 */
10981
10982/*
10983 * set the path ways for 2 channel output
10984 * need to set the codec line out and mic 1 pin widgets to inputs
10985 */
10986static struct hda_verb alc861_threestack_ch2_init[] = {
10987 /* set pin widget 1Ah (line in) for input */
10988 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010989 /* set pin widget 18h (mic1/2) for input, for mic also enable
10990 * the vref
10991 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010992 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10993
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010994 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10995#if 0
10996 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10997 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10998#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010999 { } /* end */
11000};
11001/*
11002 * 6ch mode
11003 * need to set the codec line out and mic 1 pin widgets to outputs
11004 */
11005static struct hda_verb alc861_threestack_ch6_init[] = {
11006 /* set pin widget 1Ah (line in) for output (Back Surround)*/
11007 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11008 /* set pin widget 18h (mic1) for output (CLFE)*/
11009 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11010
11011 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011012 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011013
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011014 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
11015#if 0
11016 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
11017 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
11018#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011019 { } /* end */
11020};
11021
11022static struct hda_channel_mode alc861_threestack_modes[2] = {
11023 { 2, alc861_threestack_ch2_init },
11024 { 6, alc861_threestack_ch6_init },
11025};
Takashi Iwai22309c32006-08-09 16:57:28 +020011026/* Set mic1 as input and unmute the mixer */
11027static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
11028 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11029 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
11030 { } /* end */
11031};
11032/* Set mic1 as output and mute mixer */
11033static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
11034 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11035 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
11036 { } /* end */
11037};
11038
11039static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
11040 { 2, alc861_uniwill_m31_ch2_init },
11041 { 4, alc861_uniwill_m31_ch4_init },
11042};
Kailang Yangdf694da2005-12-05 19:42:22 +010011043
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011044/* Set mic1 and line-in as input and unmute the mixer */
11045static struct hda_verb alc861_asus_ch2_init[] = {
11046 /* set pin widget 1Ah (line in) for input */
11047 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011048 /* set pin widget 18h (mic1/2) for input, for mic also enable
11049 * the vref
11050 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011051 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11052
11053 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
11054#if 0
11055 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
11056 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
11057#endif
11058 { } /* end */
11059};
11060/* Set mic1 nad line-in as output and mute mixer */
11061static struct hda_verb alc861_asus_ch6_init[] = {
11062 /* set pin widget 1Ah (line in) for output (Back Surround)*/
11063 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11064 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
11065 /* set pin widget 18h (mic1) for output (CLFE)*/
11066 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11067 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
11068 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
11069 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
11070
11071 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
11072#if 0
11073 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
11074 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
11075#endif
11076 { } /* end */
11077};
11078
11079static struct hda_channel_mode alc861_asus_modes[2] = {
11080 { 2, alc861_asus_ch2_init },
11081 { 6, alc861_asus_ch6_init },
11082};
11083
Kailang Yangdf694da2005-12-05 19:42:22 +010011084/* patch-ALC861 */
11085
11086static struct snd_kcontrol_new alc861_base_mixer[] = {
11087 /* output mixer control */
11088 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11089 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11090 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11091 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11092 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
11093
11094 /*Input mixer control */
11095 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11096 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
11097 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11098 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11099 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11100 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11101 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11102 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11103 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
11104 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011105
Kailang Yangdf694da2005-12-05 19:42:22 +010011106 /* Capture mixer control */
11107 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11108 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11109 {
11110 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11111 .name = "Capture Source",
11112 .count = 1,
11113 .info = alc_mux_enum_info,
11114 .get = alc_mux_enum_get,
11115 .put = alc_mux_enum_put,
11116 },
11117 { } /* end */
11118};
11119
11120static struct snd_kcontrol_new alc861_3ST_mixer[] = {
11121 /* output mixer control */
11122 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11123 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11124 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11125 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11126 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
11127
11128 /* Input mixer control */
11129 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11130 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
11131 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11132 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11133 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11134 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11135 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11136 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11137 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
11138 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011139
Kailang Yangdf694da2005-12-05 19:42:22 +010011140 /* Capture mixer control */
11141 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11142 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11143 {
11144 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11145 .name = "Capture Source",
11146 .count = 1,
11147 .info = alc_mux_enum_info,
11148 .get = alc_mux_enum_get,
11149 .put = alc_mux_enum_put,
11150 },
11151 {
11152 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11153 .name = "Channel Mode",
11154 .info = alc_ch_mode_info,
11155 .get = alc_ch_mode_get,
11156 .put = alc_ch_mode_put,
11157 .private_value = ARRAY_SIZE(alc861_threestack_modes),
11158 },
11159 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011160};
11161
Takashi Iwaid1d985f2006-11-23 19:27:12 +010011162static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011163 /* output mixer control */
11164 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11165 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11166 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11167
11168 /*Capture mixer control */
11169 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11170 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11171 {
11172 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11173 .name = "Capture Source",
11174 .count = 1,
11175 .info = alc_mux_enum_info,
11176 .get = alc_mux_enum_get,
11177 .put = alc_mux_enum_put,
11178 },
11179
11180 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011181};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011182
Takashi Iwai22309c32006-08-09 16:57:28 +020011183static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
11184 /* output mixer control */
11185 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11186 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11187 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11188 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11189 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
11190
11191 /* Input mixer control */
11192 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11193 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
11194 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11195 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11196 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11197 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11198 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11199 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11200 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
11201 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011202
Takashi Iwai22309c32006-08-09 16:57:28 +020011203 /* Capture mixer control */
11204 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11205 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11206 {
11207 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11208 .name = "Capture Source",
11209 .count = 1,
11210 .info = alc_mux_enum_info,
11211 .get = alc_mux_enum_get,
11212 .put = alc_mux_enum_put,
11213 },
11214 {
11215 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11216 .name = "Channel Mode",
11217 .info = alc_ch_mode_info,
11218 .get = alc_ch_mode_get,
11219 .put = alc_ch_mode_put,
11220 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
11221 },
11222 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011223};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011224
11225static struct snd_kcontrol_new alc861_asus_mixer[] = {
11226 /* output mixer control */
11227 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11228 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11229 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11230 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11231 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
11232
11233 /* Input mixer control */
11234 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11235 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11236 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11237 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11238 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11239 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11240 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11241 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11242 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011243 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
11244
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011245 /* Capture mixer control */
11246 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11247 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11248 {
11249 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11250 .name = "Capture Source",
11251 .count = 1,
11252 .info = alc_mux_enum_info,
11253 .get = alc_mux_enum_get,
11254 .put = alc_mux_enum_put,
11255 },
11256 {
11257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11258 .name = "Channel Mode",
11259 .info = alc_ch_mode_info,
11260 .get = alc_ch_mode_get,
11261 .put = alc_ch_mode_put,
11262 .private_value = ARRAY_SIZE(alc861_asus_modes),
11263 },
11264 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011265};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011266
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011267/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010011268static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011269 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11270 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11271 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
11272 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
11273 { }
11274};
11275
Kailang Yangdf694da2005-12-05 19:42:22 +010011276/*
11277 * generic initialization of ADC, input mixers and output mixers
11278 */
11279static struct hda_verb alc861_base_init_verbs[] = {
11280 /*
11281 * Unmute ADC0 and set the default input to mic-in
11282 */
11283 /* port-A for surround (rear panel) */
11284 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11285 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
11286 /* port-B for mic-in (rear panel) with vref */
11287 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11288 /* port-C for line-in (rear panel) */
11289 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11290 /* port-D for Front */
11291 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11292 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11293 /* port-E for HP out (front panel) */
11294 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11295 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011296 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011297 /* port-F for mic-in (front panel) with vref */
11298 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11299 /* port-G for CLFE (rear panel) */
11300 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11301 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
11302 /* port-H for side (rear panel) */
11303 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11304 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
11305 /* CD-in */
11306 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11307 /* route front mic to ADC1*/
11308 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11309 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11310
11311 /* Unmute DAC0~3 & spdif out*/
11312 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11313 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11314 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11315 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11316 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11317
11318 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11319 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11320 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11321 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11322 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11323
11324 /* Unmute Stereo Mixer 15 */
11325 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11327 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011328 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011329
11330 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11331 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11332 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11333 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11334 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11335 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11336 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11337 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011338 /* hp used DAC 3 (Front) */
11339 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011340 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11341
11342 { }
11343};
11344
11345static struct hda_verb alc861_threestack_init_verbs[] = {
11346 /*
11347 * Unmute ADC0 and set the default input to mic-in
11348 */
11349 /* port-A for surround (rear panel) */
11350 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11351 /* port-B for mic-in (rear panel) with vref */
11352 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11353 /* port-C for line-in (rear panel) */
11354 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11355 /* port-D for Front */
11356 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11357 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11358 /* port-E for HP out (front panel) */
11359 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11360 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011361 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011362 /* port-F for mic-in (front panel) with vref */
11363 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11364 /* port-G for CLFE (rear panel) */
11365 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11366 /* port-H for side (rear panel) */
11367 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11368 /* CD-in */
11369 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11370 /* route front mic to ADC1*/
11371 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11372 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11373 /* Unmute DAC0~3 & spdif out*/
11374 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11375 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11376 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11377 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11378 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11379
11380 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11381 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11382 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11383 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11384 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11385
11386 /* Unmute Stereo Mixer 15 */
11387 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11388 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11389 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011390 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011391
11392 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11393 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11394 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11395 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11397 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11398 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11399 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011400 /* hp used DAC 3 (Front) */
11401 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011402 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11403 { }
11404};
Takashi Iwai22309c32006-08-09 16:57:28 +020011405
11406static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
11407 /*
11408 * Unmute ADC0 and set the default input to mic-in
11409 */
11410 /* port-A for surround (rear panel) */
11411 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11412 /* port-B for mic-in (rear panel) with vref */
11413 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11414 /* port-C for line-in (rear panel) */
11415 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11416 /* port-D for Front */
11417 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11418 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11419 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011420 /* this has to be set to VREF80 */
11421 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011422 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011423 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011424 /* port-F for mic-in (front panel) with vref */
11425 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11426 /* port-G for CLFE (rear panel) */
11427 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11428 /* port-H for side (rear panel) */
11429 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11430 /* CD-in */
11431 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11432 /* route front mic to ADC1*/
11433 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11434 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11435 /* Unmute DAC0~3 & spdif out*/
11436 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11437 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11438 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11439 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11440 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11441
11442 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11443 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11444 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11445 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11446 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11447
11448 /* Unmute Stereo Mixer 15 */
11449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11450 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11451 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011452 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020011453
11454 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11455 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11456 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11457 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11458 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11459 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11460 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11461 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011462 /* hp used DAC 3 (Front) */
11463 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020011464 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11465 { }
11466};
11467
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011468static struct hda_verb alc861_asus_init_verbs[] = {
11469 /*
11470 * Unmute ADC0 and set the default input to mic-in
11471 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011472 /* port-A for surround (rear panel)
11473 * according to codec#0 this is the HP jack
11474 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011475 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
11476 /* route front PCM to HP */
11477 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
11478 /* port-B for mic-in (rear panel) with vref */
11479 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11480 /* port-C for line-in (rear panel) */
11481 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11482 /* port-D for Front */
11483 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11484 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11485 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011486 /* this has to be set to VREF80 */
11487 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011488 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011489 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011490 /* port-F for mic-in (front panel) with vref */
11491 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11492 /* port-G for CLFE (rear panel) */
11493 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11494 /* port-H for side (rear panel) */
11495 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11496 /* CD-in */
11497 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11498 /* route front mic to ADC1*/
11499 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11500 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11501 /* Unmute DAC0~3 & spdif out*/
11502 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11503 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11504 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11505 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11506 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11507 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11508 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11509 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11510 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11511 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11512
11513 /* Unmute Stereo Mixer 15 */
11514 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11515 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11516 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011517 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011518
11519 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11520 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11521 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11522 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11523 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11524 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11525 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11526 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011527 /* hp used DAC 3 (Front) */
11528 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011529 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11530 { }
11531};
11532
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011533/* additional init verbs for ASUS laptops */
11534static struct hda_verb alc861_asus_laptop_init_verbs[] = {
11535 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
11536 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
11537 { }
11538};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011539
Kailang Yangdf694da2005-12-05 19:42:22 +010011540/*
11541 * generic initialization of ADC, input mixers and output mixers
11542 */
11543static struct hda_verb alc861_auto_init_verbs[] = {
11544 /*
11545 * Unmute ADC0 and set the default input to mic-in
11546 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011547 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010011548 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11549
11550 /* Unmute DAC0~3 & spdif out*/
11551 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11552 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11553 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11554 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11555 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11556
11557 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11558 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11559 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11560 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11561 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11562
11563 /* Unmute Stereo Mixer 15 */
11564 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11565 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11566 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11567 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
11568
11569 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11570 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11571 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11572 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11573 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11574 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11575 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11576 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11577
11578 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11579 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011580 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11581 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011582 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11583 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011584 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11585 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011586
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011587 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011588
11589 { }
11590};
11591
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011592static struct hda_verb alc861_toshiba_init_verbs[] = {
11593 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011594
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011595 { }
11596};
11597
11598/* toggle speaker-output according to the hp-jack state */
11599static void alc861_toshiba_automute(struct hda_codec *codec)
11600{
11601 unsigned int present;
11602
11603 present = snd_hda_codec_read(codec, 0x0f, 0,
11604 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011605 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
11606 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
11607 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
11608 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011609}
11610
11611static void alc861_toshiba_unsol_event(struct hda_codec *codec,
11612 unsigned int res)
11613{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011614 if ((res >> 26) == ALC880_HP_EVENT)
11615 alc861_toshiba_automute(codec);
11616}
11617
Kailang Yangdf694da2005-12-05 19:42:22 +010011618/* pcm configuration: identiacal with ALC880 */
11619#define alc861_pcm_analog_playback alc880_pcm_analog_playback
11620#define alc861_pcm_analog_capture alc880_pcm_analog_capture
11621#define alc861_pcm_digital_playback alc880_pcm_digital_playback
11622#define alc861_pcm_digital_capture alc880_pcm_digital_capture
11623
11624
11625#define ALC861_DIGOUT_NID 0x07
11626
11627static struct hda_channel_mode alc861_8ch_modes[1] = {
11628 { 8, NULL }
11629};
11630
11631static hda_nid_t alc861_dac_nids[4] = {
11632 /* front, surround, clfe, side */
11633 0x03, 0x06, 0x05, 0x04
11634};
11635
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011636static hda_nid_t alc660_dac_nids[3] = {
11637 /* front, clfe, surround */
11638 0x03, 0x05, 0x06
11639};
11640
Kailang Yangdf694da2005-12-05 19:42:22 +010011641static hda_nid_t alc861_adc_nids[1] = {
11642 /* ADC0-2 */
11643 0x08,
11644};
11645
11646static struct hda_input_mux alc861_capture_source = {
11647 .num_items = 5,
11648 .items = {
11649 { "Mic", 0x0 },
11650 { "Front Mic", 0x3 },
11651 { "Line", 0x1 },
11652 { "CD", 0x4 },
11653 { "Mixer", 0x5 },
11654 },
11655};
11656
11657/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011658static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
11659 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011660{
11661 int i;
11662 hda_nid_t nid;
11663
11664 spec->multiout.dac_nids = spec->private_dac_nids;
11665 for (i = 0; i < cfg->line_outs; i++) {
11666 nid = cfg->line_out_pins[i];
11667 if (nid) {
11668 if (i >= ARRAY_SIZE(alc861_dac_nids))
11669 continue;
11670 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
11671 }
11672 }
11673 spec->multiout.num_dacs = cfg->line_outs;
11674 return 0;
11675}
11676
11677/* add playback controls from the parsed DAC table */
11678static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
11679 const struct auto_pin_cfg *cfg)
11680{
11681 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011682 static const char *chname[4] = {
11683 "Front", "Surround", NULL /*CLFE*/, "Side"
11684 };
Kailang Yangdf694da2005-12-05 19:42:22 +010011685 hda_nid_t nid;
11686 int i, idx, err;
11687
11688 for (i = 0; i < cfg->line_outs; i++) {
11689 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011690 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010011691 continue;
11692 if (nid == 0x05) {
11693 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011694 err = add_control(spec, ALC_CTL_BIND_MUTE,
11695 "Center Playback Switch",
11696 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
11697 HDA_OUTPUT));
11698 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011699 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011700 err = add_control(spec, ALC_CTL_BIND_MUTE,
11701 "LFE Playback Switch",
11702 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11703 HDA_OUTPUT));
11704 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011705 return err;
11706 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011707 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
11708 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010011709 if (nid == alc861_dac_nids[idx])
11710 break;
11711 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011712 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
11713 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11714 HDA_OUTPUT));
11715 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011716 return err;
11717 }
11718 }
11719 return 0;
11720}
11721
11722static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
11723{
11724 int err;
11725 hda_nid_t nid;
11726
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011727 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010011728 return 0;
11729
11730 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
11731 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011732 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11733 "Headphone Playback Switch",
11734 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11735 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011736 return err;
11737 spec->multiout.hp_nid = nid;
11738 }
11739 return 0;
11740}
11741
11742/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011743static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
11744 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011745{
Kailang Yangdf694da2005-12-05 19:42:22 +010011746 struct hda_input_mux *imux = &spec->private_imux;
11747 int i, err, idx, idx1;
11748
11749 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011750 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011751 case 0x0c:
11752 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011753 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011754 break;
11755 case 0x0f:
11756 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011757 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011758 break;
11759 case 0x0d:
11760 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011761 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011762 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011763 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010011764 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011765 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011766 break;
11767 case 0x11:
11768 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011769 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010011770 break;
11771 default:
11772 continue;
11773 }
11774
Takashi Iwai4a471b72005-12-07 13:56:29 +010011775 err = new_analog_input(spec, cfg->input_pins[i],
11776 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010011777 if (err < 0)
11778 return err;
11779
Takashi Iwai4a471b72005-12-07 13:56:29 +010011780 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010011781 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011782 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010011783 }
11784 return 0;
11785}
11786
11787static struct snd_kcontrol_new alc861_capture_mixer[] = {
11788 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11789 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11790
11791 {
11792 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11793 /* The multiple "Capture Source" controls confuse alsamixer
11794 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010011795 */
11796 /* .name = "Capture Source", */
11797 .name = "Input Source",
11798 .count = 1,
11799 .info = alc_mux_enum_info,
11800 .get = alc_mux_enum_get,
11801 .put = alc_mux_enum_put,
11802 },
11803 { } /* end */
11804};
11805
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011806static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
11807 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010011808 int pin_type, int dac_idx)
11809{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011810 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011811}
11812
11813static void alc861_auto_init_multi_out(struct hda_codec *codec)
11814{
11815 struct alc_spec *spec = codec->spec;
11816 int i;
11817
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011818 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010011819 for (i = 0; i < spec->autocfg.line_outs; i++) {
11820 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011821 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011822 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011823 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011824 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011825 }
11826}
11827
11828static void alc861_auto_init_hp_out(struct hda_codec *codec)
11829{
11830 struct alc_spec *spec = codec->spec;
11831 hda_nid_t pin;
11832
Takashi Iwaieb06ed82006-09-20 17:10:27 +020011833 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011834 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011835 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
11836 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011837 pin = spec->autocfg.speaker_pins[0];
11838 if (pin)
11839 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010011840}
11841
11842static void alc861_auto_init_analog_input(struct hda_codec *codec)
11843{
11844 struct alc_spec *spec = codec->spec;
11845 int i;
11846
11847 for (i = 0; i < AUTO_PIN_LAST; i++) {
11848 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011849 if (nid >= 0x0c && nid <= 0x11) {
11850 snd_hda_codec_write(codec, nid, 0,
11851 AC_VERB_SET_PIN_WIDGET_CONTROL,
11852 i <= AUTO_PIN_FRONT_MIC ?
11853 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010011854 }
11855 }
11856}
11857
11858/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011859/* return 1 if successful, 0 if the proper config is not found,
11860 * or a negative error code
11861 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011862static int alc861_parse_auto_config(struct hda_codec *codec)
11863{
11864 struct alc_spec *spec = codec->spec;
11865 int err;
11866 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
11867
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011868 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11869 alc861_ignore);
11870 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011871 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011872 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010011873 return 0; /* can't find valid BIOS pin config */
11874
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011875 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
11876 if (err < 0)
11877 return err;
11878 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
11879 if (err < 0)
11880 return err;
11881 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
11882 if (err < 0)
11883 return err;
11884 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
11885 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011886 return err;
11887
11888 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11889
11890 if (spec->autocfg.dig_out_pin)
11891 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
11892
11893 if (spec->kctl_alloc)
11894 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11895
11896 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
11897
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011898 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010011899 spec->input_mux = &spec->private_imux;
11900
11901 spec->adc_nids = alc861_adc_nids;
11902 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
11903 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
11904 spec->num_mixers++;
11905
11906 return 1;
11907}
11908
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011909/* additional initialization for auto-configuration model */
11910static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011911{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011912 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011913 alc861_auto_init_multi_out(codec);
11914 alc861_auto_init_hp_out(codec);
11915 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011916 if (spec->unsol_event)
11917 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011918}
11919
Takashi Iwaicb53c622007-08-10 17:21:45 +020011920#ifdef CONFIG_SND_HDA_POWER_SAVE
11921static struct hda_amp_list alc861_loopbacks[] = {
11922 { 0x15, HDA_INPUT, 0 },
11923 { 0x15, HDA_INPUT, 1 },
11924 { 0x15, HDA_INPUT, 2 },
11925 { 0x15, HDA_INPUT, 3 },
11926 { } /* end */
11927};
11928#endif
11929
Kailang Yangdf694da2005-12-05 19:42:22 +010011930
11931/*
11932 * configuration and preset
11933 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011934static const char *alc861_models[ALC861_MODEL_LAST] = {
11935 [ALC861_3ST] = "3stack",
11936 [ALC660_3ST] = "3stack-660",
11937 [ALC861_3ST_DIG] = "3stack-dig",
11938 [ALC861_6ST_DIG] = "6stack-dig",
11939 [ALC861_UNIWILL_M31] = "uniwill-m31",
11940 [ALC861_TOSHIBA] = "toshiba",
11941 [ALC861_ASUS] = "asus",
11942 [ALC861_ASUS_LAPTOP] = "asus-laptop",
11943 [ALC861_AUTO] = "auto",
11944};
11945
11946static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010011947 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011948 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11949 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11950 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011951 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020011952 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010011953 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020011954 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
11955 * Any other models that need this preset?
11956 */
11957 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020011958 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
11959 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011960 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
11961 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
11962 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
11963 /* FIXME: the below seems conflict */
11964 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
11965 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
11966 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010011967 {}
11968};
11969
11970static struct alc_config_preset alc861_presets[] = {
11971 [ALC861_3ST] = {
11972 .mixers = { alc861_3ST_mixer },
11973 .init_verbs = { alc861_threestack_init_verbs },
11974 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11975 .dac_nids = alc861_dac_nids,
11976 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11977 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011978 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011979 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11980 .adc_nids = alc861_adc_nids,
11981 .input_mux = &alc861_capture_source,
11982 },
11983 [ALC861_3ST_DIG] = {
11984 .mixers = { alc861_base_mixer },
11985 .init_verbs = { alc861_threestack_init_verbs },
11986 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11987 .dac_nids = alc861_dac_nids,
11988 .dig_out_nid = ALC861_DIGOUT_NID,
11989 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11990 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011991 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011992 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11993 .adc_nids = alc861_adc_nids,
11994 .input_mux = &alc861_capture_source,
11995 },
11996 [ALC861_6ST_DIG] = {
11997 .mixers = { alc861_base_mixer },
11998 .init_verbs = { alc861_base_init_verbs },
11999 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12000 .dac_nids = alc861_dac_nids,
12001 .dig_out_nid = ALC861_DIGOUT_NID,
12002 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
12003 .channel_mode = alc861_8ch_modes,
12004 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12005 .adc_nids = alc861_adc_nids,
12006 .input_mux = &alc861_capture_source,
12007 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012008 [ALC660_3ST] = {
12009 .mixers = { alc861_3ST_mixer },
12010 .init_verbs = { alc861_threestack_init_verbs },
12011 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
12012 .dac_nids = alc660_dac_nids,
12013 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
12014 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020012015 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012016 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12017 .adc_nids = alc861_adc_nids,
12018 .input_mux = &alc861_capture_source,
12019 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012020 [ALC861_UNIWILL_M31] = {
12021 .mixers = { alc861_uniwill_m31_mixer },
12022 .init_verbs = { alc861_uniwill_m31_init_verbs },
12023 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12024 .dac_nids = alc861_dac_nids,
12025 .dig_out_nid = ALC861_DIGOUT_NID,
12026 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
12027 .channel_mode = alc861_uniwill_m31_modes,
12028 .need_dac_fix = 1,
12029 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12030 .adc_nids = alc861_adc_nids,
12031 .input_mux = &alc861_capture_source,
12032 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012033 [ALC861_TOSHIBA] = {
12034 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012035 .init_verbs = { alc861_base_init_verbs,
12036 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012037 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12038 .dac_nids = alc861_dac_nids,
12039 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
12040 .channel_mode = alc883_3ST_2ch_modes,
12041 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12042 .adc_nids = alc861_adc_nids,
12043 .input_mux = &alc861_capture_source,
12044 .unsol_event = alc861_toshiba_unsol_event,
12045 .init_hook = alc861_toshiba_automute,
12046 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012047 [ALC861_ASUS] = {
12048 .mixers = { alc861_asus_mixer },
12049 .init_verbs = { alc861_asus_init_verbs },
12050 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12051 .dac_nids = alc861_dac_nids,
12052 .dig_out_nid = ALC861_DIGOUT_NID,
12053 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
12054 .channel_mode = alc861_asus_modes,
12055 .need_dac_fix = 1,
12056 .hp_nid = 0x06,
12057 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12058 .adc_nids = alc861_adc_nids,
12059 .input_mux = &alc861_capture_source,
12060 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012061 [ALC861_ASUS_LAPTOP] = {
12062 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
12063 .init_verbs = { alc861_asus_init_verbs,
12064 alc861_asus_laptop_init_verbs },
12065 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12066 .dac_nids = alc861_dac_nids,
12067 .dig_out_nid = ALC861_DIGOUT_NID,
12068 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
12069 .channel_mode = alc883_3ST_2ch_modes,
12070 .need_dac_fix = 1,
12071 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12072 .adc_nids = alc861_adc_nids,
12073 .input_mux = &alc861_capture_source,
12074 },
12075};
Kailang Yangdf694da2005-12-05 19:42:22 +010012076
12077
12078static int patch_alc861(struct hda_codec *codec)
12079{
12080 struct alc_spec *spec;
12081 int board_config;
12082 int err;
12083
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012084 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012085 if (spec == NULL)
12086 return -ENOMEM;
12087
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012088 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012089
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012090 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
12091 alc861_models,
12092 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012093
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012094 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012095 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
12096 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012097 board_config = ALC861_AUTO;
12098 }
12099
12100 if (board_config == ALC861_AUTO) {
12101 /* automatic parse from the BIOS config */
12102 err = alc861_parse_auto_config(codec);
12103 if (err < 0) {
12104 alc_free(codec);
12105 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012106 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012107 printk(KERN_INFO
12108 "hda_codec: Cannot set up configuration "
12109 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012110 board_config = ALC861_3ST_DIG;
12111 }
12112 }
12113
12114 if (board_config != ALC861_AUTO)
12115 setup_preset(spec, &alc861_presets[board_config]);
12116
12117 spec->stream_name_analog = "ALC861 Analog";
12118 spec->stream_analog_playback = &alc861_pcm_analog_playback;
12119 spec->stream_analog_capture = &alc861_pcm_analog_capture;
12120
12121 spec->stream_name_digital = "ALC861 Digital";
12122 spec->stream_digital_playback = &alc861_pcm_digital_playback;
12123 spec->stream_digital_capture = &alc861_pcm_digital_capture;
12124
Takashi Iwai2134ea42008-01-10 16:53:55 +010012125 spec->vmaster_nid = 0x03;
12126
Kailang Yangdf694da2005-12-05 19:42:22 +010012127 codec->patch_ops = alc_patch_ops;
12128 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012129 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012130#ifdef CONFIG_SND_HDA_POWER_SAVE
12131 if (!spec->loopback.amplist)
12132 spec->loopback.amplist = alc861_loopbacks;
12133#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012134
12135 return 0;
12136}
12137
12138/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012139 * ALC861-VD support
12140 *
12141 * Based on ALC882
12142 *
12143 * In addition, an independent DAC
12144 */
12145#define ALC861VD_DIGOUT_NID 0x06
12146
12147static hda_nid_t alc861vd_dac_nids[4] = {
12148 /* front, surr, clfe, side surr */
12149 0x02, 0x03, 0x04, 0x05
12150};
12151
12152/* dac_nids for ALC660vd are in a different order - according to
12153 * Realtek's driver.
12154 * This should probably tesult in a different mixer for 6stack models
12155 * of ALC660vd codecs, but for now there is only 3stack mixer
12156 * - and it is the same as in 861vd.
12157 * adc_nids in ALC660vd are (is) the same as in 861vd
12158 */
12159static hda_nid_t alc660vd_dac_nids[3] = {
12160 /* front, rear, clfe, rear_surr */
12161 0x02, 0x04, 0x03
12162};
12163
12164static hda_nid_t alc861vd_adc_nids[1] = {
12165 /* ADC0 */
12166 0x09,
12167};
12168
Takashi Iwaie1406342008-02-11 18:32:32 +010012169static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
12170
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012171/* input MUX */
12172/* FIXME: should be a matrix-type input source selection */
12173static struct hda_input_mux alc861vd_capture_source = {
12174 .num_items = 4,
12175 .items = {
12176 { "Mic", 0x0 },
12177 { "Front Mic", 0x1 },
12178 { "Line", 0x2 },
12179 { "CD", 0x4 },
12180 },
12181};
12182
Kailang Yang272a5272007-05-14 11:00:38 +020012183static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010012184 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020012185 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010012186 { "Ext Mic", 0x0 },
12187 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020012188 },
12189};
12190
Kailang Yangd1a991a2007-08-15 16:21:59 +020012191static struct hda_input_mux alc861vd_hp_capture_source = {
12192 .num_items = 2,
12193 .items = {
12194 { "Front Mic", 0x0 },
12195 { "ATAPI Mic", 0x1 },
12196 },
12197};
12198
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012199#define alc861vd_mux_enum_info alc_mux_enum_info
12200#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010012201/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
12202#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012203
12204/*
12205 * 2ch mode
12206 */
12207static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
12208 { 2, NULL }
12209};
12210
12211/*
12212 * 6ch mode
12213 */
12214static struct hda_verb alc861vd_6stack_ch6_init[] = {
12215 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12216 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12217 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12218 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12219 { } /* end */
12220};
12221
12222/*
12223 * 8ch mode
12224 */
12225static struct hda_verb alc861vd_6stack_ch8_init[] = {
12226 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12227 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12228 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12229 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12230 { } /* end */
12231};
12232
12233static struct hda_channel_mode alc861vd_6stack_modes[2] = {
12234 { 6, alc861vd_6stack_ch6_init },
12235 { 8, alc861vd_6stack_ch8_init },
12236};
12237
12238static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
12239 {
12240 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12241 .name = "Channel Mode",
12242 .info = alc_ch_mode_info,
12243 .get = alc_ch_mode_get,
12244 .put = alc_ch_mode_put,
12245 },
12246 { } /* end */
12247};
12248
12249static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
12250 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
12251 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
12252
12253 {
12254 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12255 /* The multiple "Capture Source" controls confuse alsamixer
12256 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012257 */
12258 /* .name = "Capture Source", */
12259 .name = "Input Source",
12260 .count = 1,
12261 .info = alc861vd_mux_enum_info,
12262 .get = alc861vd_mux_enum_get,
12263 .put = alc861vd_mux_enum_put,
12264 },
12265 { } /* end */
12266};
12267
12268/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12269 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12270 */
12271static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
12272 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12273 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12274
12275 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12276 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
12277
12278 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
12279 HDA_OUTPUT),
12280 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
12281 HDA_OUTPUT),
12282 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
12283 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
12284
12285 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
12286 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
12287
12288 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12289
12290 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12291 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12292 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12293
12294 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12295 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12296 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12297
12298 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12299 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12300
12301 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12302 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12303
12304 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12305 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
12306
12307 { } /* end */
12308};
12309
12310static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
12311 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12312 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12313
12314 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12315
12316 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12317 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12318 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12319
12320 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12321 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12322 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12323
12324 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12325 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12326
12327 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12328 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12329
12330 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12331 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
12332
12333 { } /* end */
12334};
12335
Kailang Yangbdd148a2007-05-08 15:19:08 +020012336static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
12337 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12338 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
12339 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12340
12341 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12342
12343 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12344 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12345 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12346
12347 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12348 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12349 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12350
12351 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12352 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12353
12354 { } /* end */
12355};
12356
Tobin Davisb419f342008-03-07 11:57:51 +010012357/* Pin assignment: Speaker=0x14, HP = 0x15,
12358 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020012359 */
12360static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010012361 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12362 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012363 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12364 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010012365 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12366 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12367 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12368 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12369 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12370 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12371 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
12372 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012373 { } /* end */
12374};
12375
Kailang Yangd1a991a2007-08-15 16:21:59 +020012376/* Pin assignment: Speaker=0x14, Line-out = 0x15,
12377 * Front Mic=0x18, ATAPI Mic = 0x19,
12378 */
12379static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
12380 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12381 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12382 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12383 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12384 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12385 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12386 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12387 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12388
12389 { } /* end */
12390};
12391
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012392/*
12393 * generic initialization of ADC, input mixers and output mixers
12394 */
12395static struct hda_verb alc861vd_volume_init_verbs[] = {
12396 /*
12397 * Unmute ADC0 and set the default input to mic-in
12398 */
12399 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12400 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12401
12402 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
12403 * the analog-loopback mixer widget
12404 */
12405 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012406 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12407 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12408 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12409 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12410 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012411
12412 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020012413 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12414 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12415 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012416 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012417
12418 /*
12419 * Set up output mixers (0x02 - 0x05)
12420 */
12421 /* set vol=0 to output mixers */
12422 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12423 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12424 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12425 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12426
12427 /* set up input amps for analog loopback */
12428 /* Amp Indices: DAC = 0, mixer = 1 */
12429 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12430 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12431 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12432 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12433 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12434 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12435 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12436 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12437
12438 { }
12439};
12440
12441/*
12442 * 3-stack pin configuration:
12443 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
12444 */
12445static struct hda_verb alc861vd_3stack_init_verbs[] = {
12446 /*
12447 * Set pin mode and muting
12448 */
12449 /* set front pin widgets 0x14 for output */
12450 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12451 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12452 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12453
12454 /* Mic (rear) pin: input vref at 80% */
12455 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12456 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12457 /* Front Mic pin: input vref at 80% */
12458 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12459 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12460 /* Line In pin: input */
12461 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12462 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12463 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12464 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12465 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12466 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12467 /* CD pin widget for input */
12468 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12469
12470 { }
12471};
12472
12473/*
12474 * 6-stack pin configuration:
12475 */
12476static struct hda_verb alc861vd_6stack_init_verbs[] = {
12477 /*
12478 * Set pin mode and muting
12479 */
12480 /* set front pin widgets 0x14 for output */
12481 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12482 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12483 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12484
12485 /* Rear Pin: output 1 (0x0d) */
12486 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12487 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12488 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12489 /* CLFE Pin: output 2 (0x0e) */
12490 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12491 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12492 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
12493 /* Side Pin: output 3 (0x0f) */
12494 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12495 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12496 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
12497
12498 /* Mic (rear) pin: input vref at 80% */
12499 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12500 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12501 /* Front Mic pin: input vref at 80% */
12502 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12503 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12504 /* Line In pin: input */
12505 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12506 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12507 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12508 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12509 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12510 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12511 /* CD pin widget for input */
12512 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12513
12514 { }
12515};
12516
Kailang Yangbdd148a2007-05-08 15:19:08 +020012517static struct hda_verb alc861vd_eapd_verbs[] = {
12518 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12519 { }
12520};
12521
12522static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
12523 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12524 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12525 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12526 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12527 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12528 {}
12529};
12530
12531/* toggle speaker-output according to the hp-jack state */
12532static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
12533{
12534 unsigned int present;
12535 unsigned char bits;
12536
12537 present = snd_hda_codec_read(codec, 0x1b, 0,
12538 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012539 bits = present ? HDA_AMP_MUTE : 0;
12540 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12541 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012542}
12543
12544static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
12545{
12546 unsigned int present;
12547 unsigned char bits;
12548
12549 present = snd_hda_codec_read(codec, 0x18, 0,
12550 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012551 bits = present ? HDA_AMP_MUTE : 0;
12552 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
12553 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012554}
12555
12556static void alc861vd_lenovo_automute(struct hda_codec *codec)
12557{
12558 alc861vd_lenovo_hp_automute(codec);
12559 alc861vd_lenovo_mic_automute(codec);
12560}
12561
12562static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
12563 unsigned int res)
12564{
12565 switch (res >> 26) {
12566 case ALC880_HP_EVENT:
12567 alc861vd_lenovo_hp_automute(codec);
12568 break;
12569 case ALC880_MIC_EVENT:
12570 alc861vd_lenovo_mic_automute(codec);
12571 break;
12572 }
12573}
12574
Kailang Yang272a5272007-05-14 11:00:38 +020012575static struct hda_verb alc861vd_dallas_verbs[] = {
12576 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12577 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12578 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12579 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12580
12581 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12582 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12583 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12584 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12585 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12586 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12587 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12588 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12589
12590 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12591 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12592 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12593 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12594 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12595 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12596 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12597 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12598
12599 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12600 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12601 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12602 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12603 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12604 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12605 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12606 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12607
12608 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12609 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12610 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12611 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12612
12613 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12614 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12615 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12616
12617 { } /* end */
12618};
12619
12620/* toggle speaker-output according to the hp-jack state */
12621static void alc861vd_dallas_automute(struct hda_codec *codec)
12622{
12623 unsigned int present;
12624
12625 present = snd_hda_codec_read(codec, 0x15, 0,
12626 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012627 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12628 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020012629}
12630
12631static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
12632{
12633 if ((res >> 26) == ALC880_HP_EVENT)
12634 alc861vd_dallas_automute(codec);
12635}
12636
Takashi Iwaicb53c622007-08-10 17:21:45 +020012637#ifdef CONFIG_SND_HDA_POWER_SAVE
12638#define alc861vd_loopbacks alc880_loopbacks
12639#endif
12640
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012641/* pcm configuration: identiacal with ALC880 */
12642#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
12643#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
12644#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
12645#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
12646
12647/*
12648 * configuration and preset
12649 */
12650static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
12651 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012652 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012653 [ALC861VD_3ST] = "3stack",
12654 [ALC861VD_3ST_DIG] = "3stack-digout",
12655 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020012656 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020012657 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012658 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012659 [ALC861VD_AUTO] = "auto",
12660};
12661
12662static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012663 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
12664 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010012665 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012666 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020012667 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012668 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012669 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020012670 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020012671 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020012672 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010012673 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020012674 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012675 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
12676 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020012677 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012678 {}
12679};
12680
12681static struct alc_config_preset alc861vd_presets[] = {
12682 [ALC660VD_3ST] = {
12683 .mixers = { alc861vd_3st_mixer },
12684 .init_verbs = { alc861vd_volume_init_verbs,
12685 alc861vd_3stack_init_verbs },
12686 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12687 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012688 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12689 .channel_mode = alc861vd_3stack_2ch_modes,
12690 .input_mux = &alc861vd_capture_source,
12691 },
Mike Crash6963f842007-06-25 12:12:51 +020012692 [ALC660VD_3ST_DIG] = {
12693 .mixers = { alc861vd_3st_mixer },
12694 .init_verbs = { alc861vd_volume_init_verbs,
12695 alc861vd_3stack_init_verbs },
12696 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12697 .dac_nids = alc660vd_dac_nids,
12698 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020012699 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12700 .channel_mode = alc861vd_3stack_2ch_modes,
12701 .input_mux = &alc861vd_capture_source,
12702 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012703 [ALC861VD_3ST] = {
12704 .mixers = { alc861vd_3st_mixer },
12705 .init_verbs = { alc861vd_volume_init_verbs,
12706 alc861vd_3stack_init_verbs },
12707 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12708 .dac_nids = alc861vd_dac_nids,
12709 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12710 .channel_mode = alc861vd_3stack_2ch_modes,
12711 .input_mux = &alc861vd_capture_source,
12712 },
12713 [ALC861VD_3ST_DIG] = {
12714 .mixers = { alc861vd_3st_mixer },
12715 .init_verbs = { alc861vd_volume_init_verbs,
12716 alc861vd_3stack_init_verbs },
12717 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12718 .dac_nids = alc861vd_dac_nids,
12719 .dig_out_nid = ALC861VD_DIGOUT_NID,
12720 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12721 .channel_mode = alc861vd_3stack_2ch_modes,
12722 .input_mux = &alc861vd_capture_source,
12723 },
12724 [ALC861VD_6ST_DIG] = {
12725 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
12726 .init_verbs = { alc861vd_volume_init_verbs,
12727 alc861vd_6stack_init_verbs },
12728 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12729 .dac_nids = alc861vd_dac_nids,
12730 .dig_out_nid = ALC861VD_DIGOUT_NID,
12731 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
12732 .channel_mode = alc861vd_6stack_modes,
12733 .input_mux = &alc861vd_capture_source,
12734 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020012735 [ALC861VD_LENOVO] = {
12736 .mixers = { alc861vd_lenovo_mixer },
12737 .init_verbs = { alc861vd_volume_init_verbs,
12738 alc861vd_3stack_init_verbs,
12739 alc861vd_eapd_verbs,
12740 alc861vd_lenovo_unsol_verbs },
12741 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12742 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012743 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12744 .channel_mode = alc861vd_3stack_2ch_modes,
12745 .input_mux = &alc861vd_capture_source,
12746 .unsol_event = alc861vd_lenovo_unsol_event,
12747 .init_hook = alc861vd_lenovo_automute,
12748 },
Kailang Yang272a5272007-05-14 11:00:38 +020012749 [ALC861VD_DALLAS] = {
12750 .mixers = { alc861vd_dallas_mixer },
12751 .init_verbs = { alc861vd_dallas_verbs },
12752 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12753 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020012754 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12755 .channel_mode = alc861vd_3stack_2ch_modes,
12756 .input_mux = &alc861vd_dallas_capture_source,
12757 .unsol_event = alc861vd_dallas_unsol_event,
12758 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012759 },
12760 [ALC861VD_HP] = {
12761 .mixers = { alc861vd_hp_mixer },
12762 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
12763 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12764 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012765 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012766 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12767 .channel_mode = alc861vd_3stack_2ch_modes,
12768 .input_mux = &alc861vd_hp_capture_source,
12769 .unsol_event = alc861vd_dallas_unsol_event,
12770 .init_hook = alc861vd_dallas_automute,
12771 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012772};
12773
12774/*
12775 * BIOS auto configuration
12776 */
12777static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
12778 hda_nid_t nid, int pin_type, int dac_idx)
12779{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012780 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012781}
12782
12783static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
12784{
12785 struct alc_spec *spec = codec->spec;
12786 int i;
12787
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012788 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012789 for (i = 0; i <= HDA_SIDE; i++) {
12790 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012791 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012792 if (nid)
12793 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012794 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012795 }
12796}
12797
12798
12799static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
12800{
12801 struct alc_spec *spec = codec->spec;
12802 hda_nid_t pin;
12803
12804 pin = spec->autocfg.hp_pins[0];
12805 if (pin) /* connect to front and use dac 0 */
12806 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012807 pin = spec->autocfg.speaker_pins[0];
12808 if (pin)
12809 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012810}
12811
12812#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
12813#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
12814
12815static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
12816{
12817 struct alc_spec *spec = codec->spec;
12818 int i;
12819
12820 for (i = 0; i < AUTO_PIN_LAST; i++) {
12821 hda_nid_t nid = spec->autocfg.input_pins[i];
12822 if (alc861vd_is_input_pin(nid)) {
12823 snd_hda_codec_write(codec, nid, 0,
12824 AC_VERB_SET_PIN_WIDGET_CONTROL,
12825 i <= AUTO_PIN_FRONT_MIC ?
12826 PIN_VREF80 : PIN_IN);
12827 if (nid != ALC861VD_PIN_CD_NID)
12828 snd_hda_codec_write(codec, nid, 0,
12829 AC_VERB_SET_AMP_GAIN_MUTE,
12830 AMP_OUT_MUTE);
12831 }
12832 }
12833}
12834
12835#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
12836#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
12837
12838/* add playback controls from the parsed DAC table */
12839/* Based on ALC880 version. But ALC861VD has separate,
12840 * different NIDs for mute/unmute switch and volume control */
12841static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
12842 const struct auto_pin_cfg *cfg)
12843{
12844 char name[32];
12845 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
12846 hda_nid_t nid_v, nid_s;
12847 int i, err;
12848
12849 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012850 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012851 continue;
12852 nid_v = alc861vd_idx_to_mixer_vol(
12853 alc880_dac_to_idx(
12854 spec->multiout.dac_nids[i]));
12855 nid_s = alc861vd_idx_to_mixer_switch(
12856 alc880_dac_to_idx(
12857 spec->multiout.dac_nids[i]));
12858
12859 if (i == 2) {
12860 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012861 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12862 "Center Playback Volume",
12863 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
12864 HDA_OUTPUT));
12865 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012866 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012867 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12868 "LFE Playback Volume",
12869 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
12870 HDA_OUTPUT));
12871 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012872 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012873 err = add_control(spec, ALC_CTL_BIND_MUTE,
12874 "Center Playback Switch",
12875 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12876 HDA_INPUT));
12877 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012878 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012879 err = add_control(spec, ALC_CTL_BIND_MUTE,
12880 "LFE Playback Switch",
12881 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12882 HDA_INPUT));
12883 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012884 return err;
12885 } else {
12886 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012887 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12888 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
12889 HDA_OUTPUT));
12890 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012891 return err;
12892 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012893 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012894 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012895 HDA_INPUT));
12896 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012897 return err;
12898 }
12899 }
12900 return 0;
12901}
12902
12903/* add playback controls for speaker and HP outputs */
12904/* Based on ALC880 version. But ALC861VD has separate,
12905 * different NIDs for mute/unmute switch and volume control */
12906static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
12907 hda_nid_t pin, const char *pfx)
12908{
12909 hda_nid_t nid_v, nid_s;
12910 int err;
12911 char name[32];
12912
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012913 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012914 return 0;
12915
12916 if (alc880_is_fixed_pin(pin)) {
12917 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12918 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012919 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012920 spec->multiout.hp_nid = nid_v;
12921 else
12922 spec->multiout.extra_out_nid[0] = nid_v;
12923 /* control HP volume/switch on the output mixer amp */
12924 nid_v = alc861vd_idx_to_mixer_vol(
12925 alc880_fixed_pin_idx(pin));
12926 nid_s = alc861vd_idx_to_mixer_switch(
12927 alc880_fixed_pin_idx(pin));
12928
12929 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012930 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12931 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
12932 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012933 return err;
12934 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012935 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12936 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
12937 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012938 return err;
12939 } else if (alc880_is_multi_pin(pin)) {
12940 /* set manual connection */
12941 /* we have only a switch on HP-out PIN */
12942 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012943 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12944 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12945 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012946 return err;
12947 }
12948 return 0;
12949}
12950
12951/* parse the BIOS configuration and set up the alc_spec
12952 * return 1 if successful, 0 if the proper config is not found,
12953 * or a negative error code
12954 * Based on ALC880 version - had to change it to override
12955 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
12956static int alc861vd_parse_auto_config(struct hda_codec *codec)
12957{
12958 struct alc_spec *spec = codec->spec;
12959 int err;
12960 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
12961
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012962 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12963 alc861vd_ignore);
12964 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012965 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012966 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012967 return 0; /* can't find valid BIOS pin config */
12968
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012969 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12970 if (err < 0)
12971 return err;
12972 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
12973 if (err < 0)
12974 return err;
12975 err = alc861vd_auto_create_extra_out(spec,
12976 spec->autocfg.speaker_pins[0],
12977 "Speaker");
12978 if (err < 0)
12979 return err;
12980 err = alc861vd_auto_create_extra_out(spec,
12981 spec->autocfg.hp_pins[0],
12982 "Headphone");
12983 if (err < 0)
12984 return err;
12985 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
12986 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012987 return err;
12988
12989 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12990
12991 if (spec->autocfg.dig_out_pin)
12992 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
12993
12994 if (spec->kctl_alloc)
12995 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12996
12997 spec->init_verbs[spec->num_init_verbs++]
12998 = alc861vd_volume_init_verbs;
12999
13000 spec->num_mux_defs = 1;
13001 spec->input_mux = &spec->private_imux;
13002
Takashi Iwai776e1842007-08-29 15:07:11 +020013003 err = alc_auto_add_mic_boost(codec);
13004 if (err < 0)
13005 return err;
13006
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013007 return 1;
13008}
13009
13010/* additional initialization for auto-configuration model */
13011static void alc861vd_auto_init(struct hda_codec *codec)
13012{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013013 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013014 alc861vd_auto_init_multi_out(codec);
13015 alc861vd_auto_init_hp_out(codec);
13016 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013017 if (spec->unsol_event)
13018 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013019}
13020
13021static int patch_alc861vd(struct hda_codec *codec)
13022{
13023 struct alc_spec *spec;
13024 int err, board_config;
13025
13026 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13027 if (spec == NULL)
13028 return -ENOMEM;
13029
13030 codec->spec = spec;
13031
13032 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
13033 alc861vd_models,
13034 alc861vd_cfg_tbl);
13035
13036 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
13037 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
13038 "ALC861VD, trying auto-probe from BIOS...\n");
13039 board_config = ALC861VD_AUTO;
13040 }
13041
13042 if (board_config == ALC861VD_AUTO) {
13043 /* automatic parse from the BIOS config */
13044 err = alc861vd_parse_auto_config(codec);
13045 if (err < 0) {
13046 alc_free(codec);
13047 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013048 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013049 printk(KERN_INFO
13050 "hda_codec: Cannot set up configuration "
13051 "from BIOS. Using base mode...\n");
13052 board_config = ALC861VD_3ST;
13053 }
13054 }
13055
13056 if (board_config != ALC861VD_AUTO)
13057 setup_preset(spec, &alc861vd_presets[board_config]);
13058
13059 spec->stream_name_analog = "ALC861VD Analog";
13060 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
13061 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
13062
13063 spec->stream_name_digital = "ALC861VD Digital";
13064 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
13065 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
13066
13067 spec->adc_nids = alc861vd_adc_nids;
13068 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010013069 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013070
13071 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
13072 spec->num_mixers++;
13073
Takashi Iwai2134ea42008-01-10 16:53:55 +010013074 spec->vmaster_nid = 0x02;
13075
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013076 codec->patch_ops = alc_patch_ops;
13077
13078 if (board_config == ALC861VD_AUTO)
13079 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013080#ifdef CONFIG_SND_HDA_POWER_SAVE
13081 if (!spec->loopback.amplist)
13082 spec->loopback.amplist = alc861vd_loopbacks;
13083#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013084
13085 return 0;
13086}
13087
13088/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013089 * ALC662 support
13090 *
13091 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
13092 * configuration. Each pin widget can choose any input DACs and a mixer.
13093 * Each ADC is connected from a mixer of all inputs. This makes possible
13094 * 6-channel independent captures.
13095 *
13096 * In addition, an independent DAC for the multi-playback (not used in this
13097 * driver yet).
13098 */
13099#define ALC662_DIGOUT_NID 0x06
13100#define ALC662_DIGIN_NID 0x0a
13101
13102static hda_nid_t alc662_dac_nids[4] = {
13103 /* front, rear, clfe, rear_surr */
13104 0x02, 0x03, 0x04
13105};
13106
13107static hda_nid_t alc662_adc_nids[1] = {
13108 /* ADC1-2 */
13109 0x09,
13110};
Takashi Iwaie1406342008-02-11 18:32:32 +010013111
Kailang Yang77a261b2008-02-19 11:38:05 +010013112static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010013113
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013114/* input MUX */
13115/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013116static struct hda_input_mux alc662_capture_source = {
13117 .num_items = 4,
13118 .items = {
13119 { "Mic", 0x0 },
13120 { "Front Mic", 0x1 },
13121 { "Line", 0x2 },
13122 { "CD", 0x4 },
13123 },
13124};
13125
13126static struct hda_input_mux alc662_lenovo_101e_capture_source = {
13127 .num_items = 2,
13128 .items = {
13129 { "Mic", 0x1 },
13130 { "Line", 0x2 },
13131 },
13132};
Kailang Yang291702f2007-10-16 14:28:03 +020013133
13134static struct hda_input_mux alc662_eeepc_capture_source = {
13135 .num_items = 2,
13136 .items = {
13137 { "i-Mic", 0x1 },
13138 { "e-Mic", 0x0 },
13139 },
13140};
13141
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013142#define alc662_mux_enum_info alc_mux_enum_info
13143#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010013144#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013145
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013146/*
13147 * 2ch mode
13148 */
13149static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
13150 { 2, NULL }
13151};
13152
13153/*
13154 * 2ch mode
13155 */
13156static struct hda_verb alc662_3ST_ch2_init[] = {
13157 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
13158 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
13159 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
13160 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
13161 { } /* end */
13162};
13163
13164/*
13165 * 6ch mode
13166 */
13167static struct hda_verb alc662_3ST_ch6_init[] = {
13168 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13169 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
13170 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
13171 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13172 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
13173 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
13174 { } /* end */
13175};
13176
13177static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
13178 { 2, alc662_3ST_ch2_init },
13179 { 6, alc662_3ST_ch6_init },
13180};
13181
13182/*
13183 * 2ch mode
13184 */
13185static struct hda_verb alc662_sixstack_ch6_init[] = {
13186 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13187 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13188 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13189 { } /* end */
13190};
13191
13192/*
13193 * 6ch mode
13194 */
13195static struct hda_verb alc662_sixstack_ch8_init[] = {
13196 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13197 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13198 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13199 { } /* end */
13200};
13201
13202static struct hda_channel_mode alc662_5stack_modes[2] = {
13203 { 2, alc662_sixstack_ch6_init },
13204 { 6, alc662_sixstack_ch8_init },
13205};
13206
13207/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13208 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13209 */
13210
13211static struct snd_kcontrol_new alc662_base_mixer[] = {
13212 /* output mixer control */
13213 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013214 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013215 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013216 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013217 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13218 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013219 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
13220 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013221 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13222
13223 /*Input mixer control */
13224 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
13225 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
13226 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
13227 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
13228 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
13229 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
13230 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
13231 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013232 { } /* end */
13233};
13234
13235static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
13236 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013237 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013238 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13239 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13240 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13241 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13242 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13243 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13244 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13245 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13246 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13247 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13248 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013249 { } /* end */
13250};
13251
13252static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
13253 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013254 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013255 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013256 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013257 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13258 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013259 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
13260 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013261 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13262 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13263 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13264 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13265 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13266 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13267 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13268 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13269 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13270 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13271 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013272 { } /* end */
13273};
13274
13275static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
13276 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13277 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010013278 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13279 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013280 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13281 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13282 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13283 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13284 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013285 { } /* end */
13286};
13287
Kailang Yang291702f2007-10-16 14:28:03 +020013288static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010013289 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020013290
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010013291 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13292 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020013293
13294 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
13295 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13296 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13297
13298 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
13299 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13300 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13301 { } /* end */
13302};
13303
Kailang Yang8c427222008-01-10 13:03:59 +010013304static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010013305 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13306 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010013307 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13308 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
13309 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13310 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
13311 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
13312 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010013313 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010013314 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
13315 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13316 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13317 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13318 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13319 { } /* end */
13320};
13321
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013322static struct snd_kcontrol_new alc662_chmode_mixer[] = {
13323 {
13324 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13325 .name = "Channel Mode",
13326 .info = alc_ch_mode_info,
13327 .get = alc_ch_mode_get,
13328 .put = alc_ch_mode_put,
13329 },
13330 { } /* end */
13331};
13332
13333static struct hda_verb alc662_init_verbs[] = {
13334 /* ADC: mute amp left and right */
13335 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13336 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13337 /* Front mixer: unmute input/output amp left and right (volume = 0) */
13338
Takashi Iwaicb53c622007-08-10 17:21:45 +020013339 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13340 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13341 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13342 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13343 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013344
Kailang Yangb60dd392007-09-20 12:50:29 +020013345 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13346 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13347 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13348 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13349 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13350 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013351
13352 /* Front Pin: output 0 (0x0c) */
13353 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13354 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13355
13356 /* Rear Pin: output 1 (0x0d) */
13357 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13358 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13359
13360 /* CLFE Pin: output 2 (0x0e) */
13361 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13362 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13363
13364 /* Mic (rear) pin: input vref at 80% */
13365 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13366 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13367 /* Front Mic pin: input vref at 80% */
13368 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13369 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13370 /* Line In pin: input */
13371 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13372 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13373 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13374 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13375 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13376 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13377 /* CD pin widget for input */
13378 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13379
13380 /* FIXME: use matrix-type input source selection */
13381 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13382 /* Input mixer */
13383 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13384 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020013387
13388 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13389 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13390 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13391 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013392 { }
13393};
13394
13395static struct hda_verb alc662_sue_init_verbs[] = {
13396 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
13397 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020013398 {}
13399};
13400
13401static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
13402 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13403 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13404 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013405};
13406
Kailang Yang8c427222008-01-10 13:03:59 +010013407/* Set Unsolicited Event*/
13408static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
13409 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13410 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13411 {}
13412};
13413
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013414/*
13415 * generic initialization of ADC, input mixers and output mixers
13416 */
13417static struct hda_verb alc662_auto_init_verbs[] = {
13418 /*
13419 * Unmute ADC and set the default input to mic-in
13420 */
13421 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13422 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13423
13424 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
13425 * mixer widget
13426 * Note: PASD motherboards uses the Line In 2 as the input for front
13427 * panel mic (mic 2)
13428 */
13429 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013430 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13431 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13432 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13433 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13434 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013435
13436 /*
13437 * Set up output mixers (0x0c - 0x0f)
13438 */
13439 /* set vol=0 to output mixers */
13440 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13441 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13442 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13443
13444 /* set up input amps for analog loopback */
13445 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020013446 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13447 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13448 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13449 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13450 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13451 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013452
13453
13454 /* FIXME: use matrix-type input source selection */
13455 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13456 /* Input mixer */
13457 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020013458 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013459 { }
13460};
13461
13462/* capture mixer elements */
13463static struct snd_kcontrol_new alc662_capture_mixer[] = {
13464 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13465 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13466 {
13467 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13468 /* The multiple "Capture Source" controls confuse alsamixer
13469 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013470 */
13471 /* .name = "Capture Source", */
13472 .name = "Input Source",
13473 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010013474 .info = alc662_mux_enum_info,
13475 .get = alc662_mux_enum_get,
13476 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013477 },
13478 { } /* end */
13479};
13480
13481static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
13482{
13483 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013484 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013485
13486 present = snd_hda_codec_read(codec, 0x14, 0,
13487 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013488 bits = present ? HDA_AMP_MUTE : 0;
13489 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13490 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013491}
13492
13493static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
13494{
13495 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013496 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013497
13498 present = snd_hda_codec_read(codec, 0x1b, 0,
13499 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013500 bits = present ? HDA_AMP_MUTE : 0;
13501 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13502 HDA_AMP_MUTE, bits);
13503 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13504 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013505}
13506
13507static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
13508 unsigned int res)
13509{
13510 if ((res >> 26) == ALC880_HP_EVENT)
13511 alc662_lenovo_101e_all_automute(codec);
13512 if ((res >> 26) == ALC880_FRONT_EVENT)
13513 alc662_lenovo_101e_ispeaker_automute(codec);
13514}
13515
Kailang Yang291702f2007-10-16 14:28:03 +020013516static void alc662_eeepc_mic_automute(struct hda_codec *codec)
13517{
13518 unsigned int present;
13519
13520 present = snd_hda_codec_read(codec, 0x18, 0,
13521 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
13522 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13523 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13524 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13525 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13526 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13527 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13528 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13529 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13530}
13531
13532/* unsolicited event for HP jack sensing */
13533static void alc662_eeepc_unsol_event(struct hda_codec *codec,
13534 unsigned int res)
13535{
13536 if ((res >> 26) == ALC880_HP_EVENT)
13537 alc262_hippo1_automute( codec );
13538
13539 if ((res >> 26) == ALC880_MIC_EVENT)
13540 alc662_eeepc_mic_automute(codec);
13541}
13542
13543static void alc662_eeepc_inithook(struct hda_codec *codec)
13544{
13545 alc262_hippo1_automute( codec );
13546 alc662_eeepc_mic_automute(codec);
13547}
13548
Kailang Yang8c427222008-01-10 13:03:59 +010013549static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
13550{
13551 unsigned int mute;
13552 unsigned int present;
13553
13554 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
13555 present = snd_hda_codec_read(codec, 0x14, 0,
13556 AC_VERB_GET_PIN_SENSE, 0);
13557 present = (present & 0x80000000) != 0;
13558 if (present) {
13559 /* mute internal speaker */
13560 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13561 HDA_AMP_MUTE, HDA_AMP_MUTE);
13562 } else {
13563 /* unmute internal speaker if necessary */
13564 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13565 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13566 HDA_AMP_MUTE, mute);
13567 }
13568}
13569
13570/* unsolicited event for HP jack sensing */
13571static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
13572 unsigned int res)
13573{
13574 if ((res >> 26) == ALC880_HP_EVENT)
13575 alc662_eeepc_ep20_automute(codec);
13576}
13577
13578static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
13579{
13580 alc662_eeepc_ep20_automute(codec);
13581}
13582
Takashi Iwaicb53c622007-08-10 17:21:45 +020013583#ifdef CONFIG_SND_HDA_POWER_SAVE
13584#define alc662_loopbacks alc880_loopbacks
13585#endif
13586
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013587
13588/* pcm configuration: identiacal with ALC880 */
13589#define alc662_pcm_analog_playback alc880_pcm_analog_playback
13590#define alc662_pcm_analog_capture alc880_pcm_analog_capture
13591#define alc662_pcm_digital_playback alc880_pcm_digital_playback
13592#define alc662_pcm_digital_capture alc880_pcm_digital_capture
13593
13594/*
13595 * configuration and preset
13596 */
13597static const char *alc662_models[ALC662_MODEL_LAST] = {
13598 [ALC662_3ST_2ch_DIG] = "3stack-dig",
13599 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
13600 [ALC662_3ST_6ch] = "3stack-6ch",
13601 [ALC662_5ST_DIG] = "6stack-dig",
13602 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020013603 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010013604 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013605 [ALC662_AUTO] = "auto",
13606};
13607
13608static struct snd_pci_quirk alc662_cfg_tbl[] = {
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010013609 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020013610 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010013611 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013612 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013613 {}
13614};
13615
13616static struct alc_config_preset alc662_presets[] = {
13617 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013618 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013619 .init_verbs = { alc662_init_verbs },
13620 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13621 .dac_nids = alc662_dac_nids,
13622 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013623 .dig_in_nid = ALC662_DIGIN_NID,
13624 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13625 .channel_mode = alc662_3ST_2ch_modes,
13626 .input_mux = &alc662_capture_source,
13627 },
13628 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013629 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13630 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013631 .init_verbs = { alc662_init_verbs },
13632 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13633 .dac_nids = alc662_dac_nids,
13634 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013635 .dig_in_nid = ALC662_DIGIN_NID,
13636 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13637 .channel_mode = alc662_3ST_6ch_modes,
13638 .need_dac_fix = 1,
13639 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013640 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013641 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013642 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13643 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013644 .init_verbs = { alc662_init_verbs },
13645 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13646 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013647 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13648 .channel_mode = alc662_3ST_6ch_modes,
13649 .need_dac_fix = 1,
13650 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013651 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013652 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013653 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
13654 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013655 .init_verbs = { alc662_init_verbs },
13656 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13657 .dac_nids = alc662_dac_nids,
13658 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013659 .dig_in_nid = ALC662_DIGIN_NID,
13660 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
13661 .channel_mode = alc662_5stack_modes,
13662 .input_mux = &alc662_capture_source,
13663 },
13664 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013665 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013666 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
13667 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13668 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013669 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13670 .channel_mode = alc662_3ST_2ch_modes,
13671 .input_mux = &alc662_lenovo_101e_capture_source,
13672 .unsol_event = alc662_lenovo_101e_unsol_event,
13673 .init_hook = alc662_lenovo_101e_all_automute,
13674 },
Kailang Yang291702f2007-10-16 14:28:03 +020013675 [ALC662_ASUS_EEEPC_P701] = {
13676 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
13677 .init_verbs = { alc662_init_verbs,
13678 alc662_eeepc_sue_init_verbs },
13679 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13680 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020013681 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13682 .channel_mode = alc662_3ST_2ch_modes,
13683 .input_mux = &alc662_eeepc_capture_source,
13684 .unsol_event = alc662_eeepc_unsol_event,
13685 .init_hook = alc662_eeepc_inithook,
13686 },
Kailang Yang8c427222008-01-10 13:03:59 +010013687 [ALC662_ASUS_EEEPC_EP20] = {
13688 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
13689 alc662_chmode_mixer },
13690 .init_verbs = { alc662_init_verbs,
13691 alc662_eeepc_ep20_sue_init_verbs },
13692 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13693 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010013694 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13695 .channel_mode = alc662_3ST_6ch_modes,
13696 .input_mux = &alc662_lenovo_101e_capture_source,
13697 .unsol_event = alc662_eeepc_ep20_unsol_event,
13698 .init_hook = alc662_eeepc_ep20_inithook,
13699 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013700
13701};
13702
13703
13704/*
13705 * BIOS auto configuration
13706 */
13707
13708/* add playback controls from the parsed DAC table */
13709static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
13710 const struct auto_pin_cfg *cfg)
13711{
13712 char name[32];
13713 static const char *chname[4] = {
13714 "Front", "Surround", NULL /*CLFE*/, "Side"
13715 };
13716 hda_nid_t nid;
13717 int i, err;
13718
13719 for (i = 0; i < cfg->line_outs; i++) {
13720 if (!spec->multiout.dac_nids[i])
13721 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020013722 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013723 if (i == 2) {
13724 /* Center/LFE */
13725 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13726 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013727 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13728 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013729 if (err < 0)
13730 return err;
13731 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13732 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013733 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13734 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013735 if (err < 0)
13736 return err;
13737 err = add_control(spec, ALC_CTL_BIND_MUTE,
13738 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013739 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
13740 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013741 if (err < 0)
13742 return err;
13743 err = add_control(spec, ALC_CTL_BIND_MUTE,
13744 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013745 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
13746 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013747 if (err < 0)
13748 return err;
13749 } else {
13750 sprintf(name, "%s Playback Volume", chname[i]);
13751 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013752 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13753 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013754 if (err < 0)
13755 return err;
13756 sprintf(name, "%s Playback Switch", chname[i]);
13757 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013758 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
13759 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013760 if (err < 0)
13761 return err;
13762 }
13763 }
13764 return 0;
13765}
13766
13767/* add playback controls for speaker and HP outputs */
13768static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
13769 const char *pfx)
13770{
13771 hda_nid_t nid;
13772 int err;
13773 char name[32];
13774
13775 if (!pin)
13776 return 0;
13777
13778 if (alc880_is_fixed_pin(pin)) {
13779 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13780 /* printk("DAC nid=%x\n",nid); */
13781 /* specify the DAC as the extra output */
13782 if (!spec->multiout.hp_nid)
13783 spec->multiout.hp_nid = nid;
13784 else
13785 spec->multiout.extra_out_nid[0] = nid;
13786 /* control HP volume/switch on the output mixer amp */
13787 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13788 sprintf(name, "%s Playback Volume", pfx);
13789 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13790 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13791 if (err < 0)
13792 return err;
13793 sprintf(name, "%s Playback Switch", pfx);
13794 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13795 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
13796 if (err < 0)
13797 return err;
13798 } else if (alc880_is_multi_pin(pin)) {
13799 /* set manual connection */
13800 /* we have only a switch on HP-out PIN */
13801 sprintf(name, "%s Playback Switch", pfx);
13802 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
13803 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
13804 if (err < 0)
13805 return err;
13806 }
13807 return 0;
13808}
13809
13810/* create playback/capture controls for input pins */
13811static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
13812 const struct auto_pin_cfg *cfg)
13813{
13814 struct hda_input_mux *imux = &spec->private_imux;
13815 int i, err, idx;
13816
13817 for (i = 0; i < AUTO_PIN_LAST; i++) {
13818 if (alc880_is_input_pin(cfg->input_pins[i])) {
13819 idx = alc880_input_pin_idx(cfg->input_pins[i]);
13820 err = new_analog_input(spec, cfg->input_pins[i],
13821 auto_pin_cfg_labels[i],
13822 idx, 0x0b);
13823 if (err < 0)
13824 return err;
13825 imux->items[imux->num_items].label =
13826 auto_pin_cfg_labels[i];
13827 imux->items[imux->num_items].index =
13828 alc880_input_pin_idx(cfg->input_pins[i]);
13829 imux->num_items++;
13830 }
13831 }
13832 return 0;
13833}
13834
13835static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
13836 hda_nid_t nid, int pin_type,
13837 int dac_idx)
13838{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013839 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013840 /* need the manual connection? */
13841 if (alc880_is_multi_pin(nid)) {
13842 struct alc_spec *spec = codec->spec;
13843 int idx = alc880_multi_pin_idx(nid);
13844 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
13845 AC_VERB_SET_CONNECT_SEL,
13846 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
13847 }
13848}
13849
13850static void alc662_auto_init_multi_out(struct hda_codec *codec)
13851{
13852 struct alc_spec *spec = codec->spec;
13853 int i;
13854
Kailang Yang8c427222008-01-10 13:03:59 +010013855 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013856 for (i = 0; i <= HDA_SIDE; i++) {
13857 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013858 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013859 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013860 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013861 i);
13862 }
13863}
13864
13865static void alc662_auto_init_hp_out(struct hda_codec *codec)
13866{
13867 struct alc_spec *spec = codec->spec;
13868 hda_nid_t pin;
13869
13870 pin = spec->autocfg.hp_pins[0];
13871 if (pin) /* connect to front */
13872 /* use dac 0 */
13873 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013874 pin = spec->autocfg.speaker_pins[0];
13875 if (pin)
13876 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013877}
13878
13879#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
13880#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
13881
13882static void alc662_auto_init_analog_input(struct hda_codec *codec)
13883{
13884 struct alc_spec *spec = codec->spec;
13885 int i;
13886
13887 for (i = 0; i < AUTO_PIN_LAST; i++) {
13888 hda_nid_t nid = spec->autocfg.input_pins[i];
13889 if (alc662_is_input_pin(nid)) {
13890 snd_hda_codec_write(codec, nid, 0,
13891 AC_VERB_SET_PIN_WIDGET_CONTROL,
13892 (i <= AUTO_PIN_FRONT_MIC ?
13893 PIN_VREF80 : PIN_IN));
13894 if (nid != ALC662_PIN_CD_NID)
13895 snd_hda_codec_write(codec, nid, 0,
13896 AC_VERB_SET_AMP_GAIN_MUTE,
13897 AMP_OUT_MUTE);
13898 }
13899 }
13900}
13901
13902static int alc662_parse_auto_config(struct hda_codec *codec)
13903{
13904 struct alc_spec *spec = codec->spec;
13905 int err;
13906 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
13907
13908 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13909 alc662_ignore);
13910 if (err < 0)
13911 return err;
13912 if (!spec->autocfg.line_outs)
13913 return 0; /* can't find valid BIOS pin config */
13914
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013915 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
13916 if (err < 0)
13917 return err;
13918 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
13919 if (err < 0)
13920 return err;
13921 err = alc662_auto_create_extra_out(spec,
13922 spec->autocfg.speaker_pins[0],
13923 "Speaker");
13924 if (err < 0)
13925 return err;
13926 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
13927 "Headphone");
13928 if (err < 0)
13929 return err;
13930 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
13931 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013932 return err;
13933
13934 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13935
13936 if (spec->autocfg.dig_out_pin)
13937 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
13938
13939 if (spec->kctl_alloc)
13940 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13941
13942 spec->num_mux_defs = 1;
13943 spec->input_mux = &spec->private_imux;
13944
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013945 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013946 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
13947 spec->num_mixers++;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013948 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013949}
13950
13951/* additional initialization for auto-configuration model */
13952static void alc662_auto_init(struct hda_codec *codec)
13953{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013954 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013955 alc662_auto_init_multi_out(codec);
13956 alc662_auto_init_hp_out(codec);
13957 alc662_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013958 if (spec->unsol_event)
13959 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013960}
13961
13962static int patch_alc662(struct hda_codec *codec)
13963{
13964 struct alc_spec *spec;
13965 int err, board_config;
13966
13967 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13968 if (!spec)
13969 return -ENOMEM;
13970
13971 codec->spec = spec;
13972
13973 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
13974 alc662_models,
13975 alc662_cfg_tbl);
13976 if (board_config < 0) {
13977 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
13978 "trying auto-probe from BIOS...\n");
13979 board_config = ALC662_AUTO;
13980 }
13981
13982 if (board_config == ALC662_AUTO) {
13983 /* automatic parse from the BIOS config */
13984 err = alc662_parse_auto_config(codec);
13985 if (err < 0) {
13986 alc_free(codec);
13987 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013988 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013989 printk(KERN_INFO
13990 "hda_codec: Cannot set up configuration "
13991 "from BIOS. Using base mode...\n");
13992 board_config = ALC662_3ST_2ch_DIG;
13993 }
13994 }
13995
13996 if (board_config != ALC662_AUTO)
13997 setup_preset(spec, &alc662_presets[board_config]);
13998
13999 spec->stream_name_analog = "ALC662 Analog";
14000 spec->stream_analog_playback = &alc662_pcm_analog_playback;
14001 spec->stream_analog_capture = &alc662_pcm_analog_capture;
14002
14003 spec->stream_name_digital = "ALC662 Digital";
14004 spec->stream_digital_playback = &alc662_pcm_digital_playback;
14005 spec->stream_digital_capture = &alc662_pcm_digital_capture;
14006
Takashi Iwaie1406342008-02-11 18:32:32 +010014007 spec->adc_nids = alc662_adc_nids;
14008 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
14009 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014010
Takashi Iwai2134ea42008-01-10 16:53:55 +010014011 spec->vmaster_nid = 0x02;
14012
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014013 codec->patch_ops = alc_patch_ops;
14014 if (board_config == ALC662_AUTO)
14015 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014016#ifdef CONFIG_SND_HDA_POWER_SAVE
14017 if (!spec->loopback.amplist)
14018 spec->loopback.amplist = alc662_loopbacks;
14019#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014020
14021 return 0;
14022}
14023
14024/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070014025 * patch entries
14026 */
14027struct hda_codec_preset snd_hda_preset_realtek[] = {
14028 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014029 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014030 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020014031 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014032 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014033 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014034 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014035 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
14036 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
14037 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014038 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
14039 .patch = patch_alc883 },
14040 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
14041 .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014042 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070014043 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014044 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014045 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014046 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014047 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070014048 {} /* terminator */
14049};