blob: c659588e26d3191300eadd4a49cbfe102c313da8 [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 Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yangdf694da2005-12-05 19:42:22 +010075 ALC260_HP_3013,
76 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010077 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020078 ALC260_WILL,
79 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010080#ifdef CONFIG_SND_DEBUG
81 ALC260_TEST,
82#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010083 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020084 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085};
86
Kailang Yangdf694da2005-12-05 19:42:22 +010087/* ALC262 models */
88enum {
89 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020090 ALC262_HIPPO,
91 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010092 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020093 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010094 ALC262_HP_BPC_D7000_WL,
95 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010096 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010097 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020098 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +020099 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200100 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200101 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100102 ALC262_LENOVO_3000,
Kailang Yangdf694da2005-12-05 19:42:22 +0100103 ALC262_AUTO,
104 ALC262_MODEL_LAST /* last tag */
105};
106
Kailang Yanga361d842007-06-05 12:30:55 +0200107/* ALC268 models */
108enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200109 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200110 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200111 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200112 ALC268_ACER,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100113 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100114 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100115#ifdef CONFIG_SND_DEBUG
116 ALC268_TEST,
117#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200118 ALC268_AUTO,
119 ALC268_MODEL_LAST /* last tag */
120};
121
Kailang Yangf6a92242007-12-13 16:52:54 +0100122/* ALC269 models */
123enum {
124 ALC269_BASIC,
125 ALC269_AUTO,
126 ALC269_MODEL_LAST /* last tag */
127};
128
Kailang Yangdf694da2005-12-05 19:42:22 +0100129/* ALC861 models */
130enum {
131 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200132 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100133 ALC861_3ST_DIG,
134 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200135 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200136 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200137 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100138 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100139 ALC861_AUTO,
140 ALC861_MODEL_LAST,
141};
142
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100143/* ALC861-VD models */
144enum {
145 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200146 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100147 ALC861VD_3ST,
148 ALC861VD_3ST_DIG,
149 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200150 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200151 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200152 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100153 ALC861VD_AUTO,
154 ALC861VD_MODEL_LAST,
155};
156
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200157/* ALC662 models */
158enum {
159 ALC662_3ST_2ch_DIG,
160 ALC662_3ST_6ch_DIG,
161 ALC662_3ST_6ch,
162 ALC662_5ST_DIG,
163 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200164 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100165 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200166 ALC663_ASUS_M51VA,
167 ALC663_ASUS_G71V,
168 ALC663_ASUS_H13,
169 ALC663_ASUS_G50V,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200170 ALC662_AUTO,
171 ALC662_MODEL_LAST,
172};
173
Kailang Yangdf694da2005-12-05 19:42:22 +0100174/* ALC882 models */
175enum {
176 ALC882_3ST_DIG,
177 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200178 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200179 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200180 ALC882_TARGA,
181 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200182 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100183 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200184 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200185 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200186 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100187 ALC882_MODEL_LAST,
188};
189
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200190/* ALC883 models */
191enum {
192 ALC883_3ST_2ch_DIG,
193 ALC883_3ST_6ch_DIG,
194 ALC883_3ST_6ch,
195 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200196 ALC883_TARGA_DIG,
197 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200198 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200199 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200200 ALC883_MEDION,
Kailang Yang272a5272007-05-14 11:00:38 +0200201 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100202 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200203 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200204 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200205 ALC888_LENOVO_MS7195_DIG,
206 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200207 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100208 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100209 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100210 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100211 ALC883_FUJITSU_PI2515,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200212 ALC883_AUTO,
213 ALC883_MODEL_LAST,
214};
215
Kailang Yangdf694da2005-12-05 19:42:22 +0100216/* for GPIO Poll */
217#define GPIO_MASK 0x03
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219struct alc_spec {
220 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100221 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 unsigned int num_mixers;
223
Kailang Yangdf694da2005-12-05 19:42:22 +0100224 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200225 * don't forget NULL
226 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200227 */
228 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Takashi Iwai16ded522005-06-10 19:58:24 +0200230 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 struct hda_pcm_stream *stream_analog_playback;
232 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100233 struct hda_pcm_stream *stream_analog_alt_playback;
234 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200236 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 struct hda_pcm_stream *stream_digital_playback;
238 struct hda_pcm_stream *stream_digital_capture;
239
240 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200241 struct hda_multi_out multiout; /* playback set-up
242 * max_channels, dacs must be set
243 * dig_out_nid and hp_nid are optional
244 */
Takashi Iwai63300792008-01-24 15:31:36 +0100245 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 /* capture */
248 unsigned int num_adc_nids;
249 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100250 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200251 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200254 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 const struct hda_input_mux *input_mux;
256 unsigned int cur_mux[3];
257
258 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100259 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200261 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100264 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200265
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200266 /* dynamic controls, init_verbs and input_mux */
267 struct auto_pin_cfg autocfg;
268 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100269 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200270 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200271 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100272
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100273 /* hooks */
274 void (*init_hook)(struct hda_codec *codec);
275 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
276
Takashi Iwai834be882006-03-01 14:16:17 +0100277 /* for pin sensing */
278 unsigned int sense_updated: 1;
279 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100280 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200281
Takashi Iwai2134ea42008-01-10 16:53:55 +0100282 /* for virtual master */
283 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200284#ifdef CONFIG_SND_HDA_POWER_SAVE
285 struct hda_loopback_check loopback;
286#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100287};
288
289/*
290 * configuration template - to be copied to the spec instance
291 */
292struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200293 struct snd_kcontrol_new *mixers[5]; /* should be identical size
294 * with spec
295 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100296 const struct hda_verb *init_verbs[5];
297 unsigned int num_dacs;
298 hda_nid_t *dac_nids;
299 hda_nid_t dig_out_nid; /* optional */
300 hda_nid_t hp_nid; /* optional */
301 unsigned int num_adc_nids;
302 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100303 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100304 hda_nid_t dig_in_nid;
305 unsigned int num_channel_mode;
306 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200307 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200308 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100309 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100310 void (*unsol_event)(struct hda_codec *, unsigned int);
311 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200312#ifdef CONFIG_SND_HDA_POWER_SAVE
313 struct hda_amp_list *loopbacks;
314#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315};
316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318/*
319 * input MUX handling
320 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200321static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
322 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
324 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
325 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200326 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
327 if (mux_idx >= spec->num_mux_defs)
328 mux_idx = 0;
329 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200332static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
333 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
336 struct alc_spec *spec = codec->spec;
337 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
338
339 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
340 return 0;
341}
342
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200343static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
347 struct alc_spec *spec = codec->spec;
348 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200349 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100350 hda_nid_t nid = spec->capsrc_nids ?
351 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200352 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100353 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357/*
358 * channel mode setting
359 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200360static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
361 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
364 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100365 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
366 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367}
368
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200369static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
370 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
373 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100374 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200375 spec->num_channel_mode,
376 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200379static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
380 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
383 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200384 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
385 spec->num_channel_mode,
386 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200387 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200388 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
389 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390}
391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100393 * Control the mode of pin widget settings via the mixer. "pc" is used
394 * instead of "%" to avoid consequences of accidently treating the % as
395 * being part of a format specifier. Maximum allowed length of a value is
396 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100397 *
398 * Note: some retasking pin complexes seem to ignore requests for input
399 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
400 * are requested. Therefore order this list so that this behaviour will not
401 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200402 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
403 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200404 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100405static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100406 "Mic 50pc bias", "Mic 80pc bias",
407 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100408};
409static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100410 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100411};
412/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200413 * in the pin being assumed to be exclusively an input or an output pin. In
414 * addition, "input" pins may or may not process the mic bias option
415 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
416 * accept requests for bias as of chip versions up to March 2006) and/or
417 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100418 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200419#define ALC_PIN_DIR_IN 0x00
420#define ALC_PIN_DIR_OUT 0x01
421#define ALC_PIN_DIR_INOUT 0x02
422#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
423#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100424
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200425/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100426 * For each direction the minimum and maximum values are given.
427 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200428static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100429 { 0, 2 }, /* ALC_PIN_DIR_IN */
430 { 3, 4 }, /* ALC_PIN_DIR_OUT */
431 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200432 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
433 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100434};
435#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
436#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
437#define alc_pin_mode_n_items(_dir) \
438 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
439
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200440static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
441 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200442{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100443 unsigned int item_num = uinfo->value.enumerated.item;
444 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
445
446 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200447 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100448 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
449
450 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
451 item_num = alc_pin_mode_min(dir);
452 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200453 return 0;
454}
455
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200456static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
457 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200458{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100459 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200460 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
461 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100462 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200463 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200464 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
465 AC_VERB_GET_PIN_WIDGET_CONTROL,
466 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200467
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100468 /* Find enumerated value for current pinctl setting */
469 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200470 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100471 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200472 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100473 return 0;
474}
475
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200476static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
477 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100478{
479 signed int change;
480 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
481 hda_nid_t nid = kcontrol->private_value & 0xffff;
482 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
483 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200484 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
485 AC_VERB_GET_PIN_WIDGET_CONTROL,
486 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100487
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200488 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100489 val = alc_pin_mode_min(dir);
490
491 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100492 if (change) {
493 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200494 snd_hda_codec_write_cache(codec, nid, 0,
495 AC_VERB_SET_PIN_WIDGET_CONTROL,
496 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100497
498 /* Also enable the retasking pin's input/output as required
499 * for the requested pin mode. Enum values of 2 or less are
500 * input modes.
501 *
502 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200503 * reduces noise slightly (particularly on input) so we'll
504 * do it. However, having both input and output buffers
505 * enabled simultaneously doesn't seem to be problematic if
506 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100507 */
508 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200509 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
510 HDA_AMP_MUTE, HDA_AMP_MUTE);
511 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
512 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100513 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200514 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
515 HDA_AMP_MUTE, HDA_AMP_MUTE);
516 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
517 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100518 }
519 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200520 return change;
521}
522
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100523#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200524 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100525 .info = alc_pin_mode_info, \
526 .get = alc_pin_mode_get, \
527 .put = alc_pin_mode_put, \
528 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100529
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100530/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
531 * together using a mask with more than one bit set. This control is
532 * currently used only by the ALC260 test model. At this stage they are not
533 * needed for any "production" models.
534 */
535#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200536#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200537
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200538static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100540{
541 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
542 hda_nid_t nid = kcontrol->private_value & 0xffff;
543 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
544 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200545 unsigned int val = snd_hda_codec_read(codec, nid, 0,
546 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100547
548 *valp = (val & mask) != 0;
549 return 0;
550}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200551static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
552 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100553{
554 signed int change;
555 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
556 hda_nid_t nid = kcontrol->private_value & 0xffff;
557 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
558 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200559 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
560 AC_VERB_GET_GPIO_DATA,
561 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100562
563 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200564 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
565 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100566 gpio_data &= ~mask;
567 else
568 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200569 snd_hda_codec_write_cache(codec, nid, 0,
570 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100571
572 return change;
573}
574#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
575 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
576 .info = alc_gpio_data_info, \
577 .get = alc_gpio_data_get, \
578 .put = alc_gpio_data_put, \
579 .private_value = nid | (mask<<16) }
580#endif /* CONFIG_SND_DEBUG */
581
Jonathan Woithe92621f12006-02-28 11:47:47 +0100582/* A switch control to allow the enabling of the digital IO pins on the
583 * ALC260. This is incredibly simplistic; the intention of this control is
584 * to provide something in the test model allowing digital outputs to be
585 * identified if present. If models are found which can utilise these
586 * outputs a more complete mixer control can be devised for those models if
587 * necessary.
588 */
589#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200590#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200591
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200592static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
593 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100594{
595 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
596 hda_nid_t nid = kcontrol->private_value & 0xffff;
597 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
598 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200599 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100600 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100601
602 *valp = (val & mask) != 0;
603 return 0;
604}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200605static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
606 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100607{
608 signed int change;
609 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
610 hda_nid_t nid = kcontrol->private_value & 0xffff;
611 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
612 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200613 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100614 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200615 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100616
617 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200618 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100619 if (val==0)
620 ctrl_data &= ~mask;
621 else
622 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200623 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
624 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100625
626 return change;
627}
628#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
629 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
630 .info = alc_spdif_ctrl_info, \
631 .get = alc_spdif_ctrl_get, \
632 .put = alc_spdif_ctrl_put, \
633 .private_value = nid | (mask<<16) }
634#endif /* CONFIG_SND_DEBUG */
635
Jonathan Woithef8225f62008-01-08 12:16:54 +0100636/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
637 * Again, this is only used in the ALC26x test models to help identify when
638 * the EAPD line must be asserted for features to work.
639 */
640#ifdef CONFIG_SND_DEBUG
641#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
642
643static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
644 struct snd_ctl_elem_value *ucontrol)
645{
646 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
647 hda_nid_t nid = kcontrol->private_value & 0xffff;
648 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
649 long *valp = ucontrol->value.integer.value;
650 unsigned int val = snd_hda_codec_read(codec, nid, 0,
651 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
652
653 *valp = (val & mask) != 0;
654 return 0;
655}
656
657static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
658 struct snd_ctl_elem_value *ucontrol)
659{
660 int change;
661 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
662 hda_nid_t nid = kcontrol->private_value & 0xffff;
663 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
664 long val = *ucontrol->value.integer.value;
665 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
666 AC_VERB_GET_EAPD_BTLENABLE,
667 0x00);
668
669 /* Set/unset the masked control bit(s) as needed */
670 change = (!val ? 0 : mask) != (ctrl_data & mask);
671 if (!val)
672 ctrl_data &= ~mask;
673 else
674 ctrl_data |= mask;
675 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
676 ctrl_data);
677
678 return change;
679}
680
681#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
682 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
683 .info = alc_eapd_ctrl_info, \
684 .get = alc_eapd_ctrl_get, \
685 .put = alc_eapd_ctrl_put, \
686 .private_value = nid | (mask<<16) }
687#endif /* CONFIG_SND_DEBUG */
688
Kailang Yangdf694da2005-12-05 19:42:22 +0100689/*
690 * set up from the preset table
691 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200692static void setup_preset(struct alc_spec *spec,
693 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100694{
695 int i;
696
697 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
698 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200699 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
700 i++)
701 spec->init_verbs[spec->num_init_verbs++] =
702 preset->init_verbs[i];
Kailang Yangdf694da2005-12-05 19:42:22 +0100703
704 spec->channel_mode = preset->channel_mode;
705 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200706 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100707
708 spec->multiout.max_channels = spec->channel_mode[0].channels;
709
710 spec->multiout.num_dacs = preset->num_dacs;
711 spec->multiout.dac_nids = preset->dac_nids;
712 spec->multiout.dig_out_nid = preset->dig_out_nid;
713 spec->multiout.hp_nid = preset->hp_nid;
714
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200715 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200716 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200717 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100718 spec->input_mux = preset->input_mux;
719
720 spec->num_adc_nids = preset->num_adc_nids;
721 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100722 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100723 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100724
725 spec->unsol_event = preset->unsol_event;
726 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200727#ifdef CONFIG_SND_HDA_POWER_SAVE
728 spec->loopback.amplist = preset->loopbacks;
729#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100730}
731
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200732/* Enable GPIO mask and set output */
733static struct hda_verb alc_gpio1_init_verbs[] = {
734 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
735 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
736 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
737 { }
738};
739
740static struct hda_verb alc_gpio2_init_verbs[] = {
741 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
742 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
743 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
744 { }
745};
746
Kailang Yangbdd148a2007-05-08 15:19:08 +0200747static struct hda_verb alc_gpio3_init_verbs[] = {
748 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
749 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
750 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
751 { }
752};
753
Kailang Yangc9b58002007-10-16 14:30:01 +0200754static void alc_sku_automute(struct hda_codec *codec)
755{
756 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200757 unsigned int present;
758 unsigned int hp_nid = spec->autocfg.hp_pins[0];
759 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
760
761 /* need to execute and sync at first */
762 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
763 present = snd_hda_codec_read(codec, hp_nid, 0,
764 AC_VERB_GET_PIN_SENSE, 0);
765 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100766 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
767 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200768}
769
770/* unsolicited event for HP jack sensing */
771static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
772{
773 if (codec->vendor_id == 0x10ec0880)
774 res >>= 28;
775 else
776 res >>= 26;
777 if (res != ALC880_HP_EVENT)
778 return;
779
780 alc_sku_automute(codec);
781}
782
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200783/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
784 * 31 ~ 16 : Manufacture ID
785 * 15 ~ 8 : SKU ID
786 * 7 ~ 0 : Assembly ID
787 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
788 */
789static void alc_subsystem_id(struct hda_codec *codec,
790 unsigned int porta, unsigned int porte,
791 unsigned int portd)
792{
Kailang Yangc9b58002007-10-16 14:30:01 +0200793 unsigned int ass, tmp, i;
794 unsigned nid;
795 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200796
Kailang Yangc9b58002007-10-16 14:30:01 +0200797 ass = codec->subsystem_id & 0xffff;
798 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
799 goto do_sku;
800
801 /*
802 * 31~30 : port conetcivity
803 * 29~21 : reserve
804 * 20 : PCBEEP input
805 * 19~16 : Check sum (15:1)
806 * 15~1 : Custom
807 * 0 : override
808 */
809 nid = 0x1d;
810 if (codec->vendor_id == 0x10ec0260)
811 nid = 0x17;
812 ass = snd_hda_codec_read(codec, nid, 0,
813 AC_VERB_GET_CONFIG_DEFAULT, 0);
814 if (!(ass & 1) && !(ass & 0x100000))
815 return;
816 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200817 return;
818
Kailang Yangc9b58002007-10-16 14:30:01 +0200819 /* check sum */
820 tmp = 0;
821 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100822 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200823 tmp++;
824 }
825 if (((ass >> 16) & 0xf) != tmp)
826 return;
827do_sku:
828 /*
829 * 0 : override
830 * 1 : Swap Jack
831 * 2 : 0 --> Desktop, 1 --> Laptop
832 * 3~5 : External Amplifier control
833 * 7~6 : Reserved
834 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200835 tmp = (ass & 0x38) >> 3; /* external Amp control */
836 switch (tmp) {
837 case 1:
838 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
839 break;
840 case 3:
841 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
842 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200843 case 7:
844 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
845 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200846 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200847 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200848 case 0x10ec0260:
849 snd_hda_codec_write(codec, 0x0f, 0,
850 AC_VERB_SET_EAPD_BTLENABLE, 2);
851 snd_hda_codec_write(codec, 0x10, 0,
852 AC_VERB_SET_EAPD_BTLENABLE, 2);
853 break;
854 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200855 case 0x10ec0267:
856 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200857 case 0x10ec0269:
858 case 0x10ec0862:
859 case 0x10ec0662:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200860 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200861 snd_hda_codec_write(codec, 0x14, 0,
862 AC_VERB_SET_EAPD_BTLENABLE, 2);
863 snd_hda_codec_write(codec, 0x15, 0,
864 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200865 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200866 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200867 switch (codec->vendor_id) {
868 case 0x10ec0260:
869 snd_hda_codec_write(codec, 0x1a, 0,
870 AC_VERB_SET_COEF_INDEX, 7);
871 tmp = snd_hda_codec_read(codec, 0x1a, 0,
872 AC_VERB_GET_PROC_COEF, 0);
873 snd_hda_codec_write(codec, 0x1a, 0,
874 AC_VERB_SET_COEF_INDEX, 7);
875 snd_hda_codec_write(codec, 0x1a, 0,
876 AC_VERB_SET_PROC_COEF,
877 tmp | 0x2010);
878 break;
879 case 0x10ec0262:
880 case 0x10ec0880:
881 case 0x10ec0882:
882 case 0x10ec0883:
883 case 0x10ec0885:
884 case 0x10ec0888:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200885 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +0200886 snd_hda_codec_write(codec, 0x20, 0,
887 AC_VERB_SET_COEF_INDEX, 7);
888 tmp = snd_hda_codec_read(codec, 0x20, 0,
889 AC_VERB_GET_PROC_COEF, 0);
890 snd_hda_codec_write(codec, 0x20, 0,
891 AC_VERB_SET_COEF_INDEX, 7);
892 snd_hda_codec_write(codec, 0x20, 0,
893 AC_VERB_SET_PROC_COEF,
894 tmp | 0x2010);
895 break;
896 case 0x10ec0267:
897 case 0x10ec0268:
898 snd_hda_codec_write(codec, 0x20, 0,
899 AC_VERB_SET_COEF_INDEX, 7);
900 tmp = snd_hda_codec_read(codec, 0x20, 0,
901 AC_VERB_GET_PROC_COEF, 0);
902 snd_hda_codec_write(codec, 0x20, 0,
903 AC_VERB_SET_COEF_INDEX, 7);
904 snd_hda_codec_write(codec, 0x20, 0,
905 AC_VERB_SET_PROC_COEF,
906 tmp | 0x3000);
907 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200908 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200909 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200910 break;
911 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200912
Kailang Yang8c427222008-01-10 13:03:59 +0100913 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200914 * when the external headphone out jack is plugged"
915 */
Kailang Yang8c427222008-01-10 13:03:59 +0100916 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200917 return;
918 /*
919 * 10~8 : Jack location
920 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
921 * 14~13: Resvered
922 * 15 : 1 --> enable the function "Mute internal speaker
923 * when the external headphone out jack is plugged"
924 */
925 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +0100926 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +0200927 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +0100928 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +0200929 else
930 return;
931 }
932
933 if (!spec->autocfg.hp_pins[0]) {
934 tmp = (ass >> 11) & 0x3; /* HP to chassis */
935 if (tmp == 0)
936 spec->autocfg.hp_pins[0] = porta;
937 else if (tmp == 1)
938 spec->autocfg.hp_pins[0] = porte;
939 else if (tmp == 2)
940 spec->autocfg.hp_pins[0] = portd;
941 else
942 return;
943 }
944
945 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
946 AC_VERB_SET_UNSOLICITED_ENABLE,
947 AC_USRSP_EN | ALC880_HP_EVENT);
948 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200949}
950
Takashi Iwai41e41f12005-06-08 14:48:49 +0200951/*
Takashi Iwaif95474e2007-07-10 00:47:43 +0200952 * Fix-up pin default configurations
953 */
954
955struct alc_pincfg {
956 hda_nid_t nid;
957 u32 val;
958};
959
960static void alc_fix_pincfg(struct hda_codec *codec,
961 const struct snd_pci_quirk *quirk,
962 const struct alc_pincfg **pinfix)
963{
964 const struct alc_pincfg *cfg;
965
966 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
967 if (!quirk)
968 return;
969
970 cfg = pinfix[quirk->value];
971 for (; cfg->nid; cfg++) {
972 int i;
973 u32 val = cfg->val;
974 for (i = 0; i < 4; i++) {
975 snd_hda_codec_write(codec, cfg->nid, 0,
976 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
977 val & 0xff);
978 val >>= 8;
979 }
980 }
981}
982
983/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200984 * ALC880 3-stack model
985 *
986 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200987 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
988 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 */
990
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200991static hda_nid_t alc880_dac_nids[4] = {
992 /* front, rear, clfe, rear_surr */
993 0x02, 0x05, 0x04, 0x03
994};
995
996static hda_nid_t alc880_adc_nids[3] = {
997 /* ADC0-2 */
998 0x07, 0x08, 0x09,
999};
1000
1001/* The datasheet says the node 0x07 is connected from inputs,
1002 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001003 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001005static hda_nid_t alc880_adc_nids_alt[2] = {
1006 /* ADC1-2 */
1007 0x08, 0x09,
1008};
1009
1010#define ALC880_DIGOUT_NID 0x06
1011#define ALC880_DIGIN_NID 0x0a
1012
1013static struct hda_input_mux alc880_capture_source = {
1014 .num_items = 4,
1015 .items = {
1016 { "Mic", 0x0 },
1017 { "Front Mic", 0x3 },
1018 { "Line", 0x2 },
1019 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001021};
1022
1023/* channel source setting (2/6 channel selection for 3-stack) */
1024/* 2ch mode */
1025static struct hda_verb alc880_threestack_ch2_init[] = {
1026 /* set line-in to input, mute it */
1027 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1028 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1029 /* set mic-in to input vref 80%, mute it */
1030 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1031 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 { } /* end */
1033};
1034
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001035/* 6ch mode */
1036static struct hda_verb alc880_threestack_ch6_init[] = {
1037 /* set line-in to output, unmute it */
1038 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1039 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1040 /* set mic-in to output, unmute it */
1041 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1042 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1043 { } /* end */
1044};
1045
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001046static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001047 { 2, alc880_threestack_ch2_init },
1048 { 6, alc880_threestack_ch6_init },
1049};
1050
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001051static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001052 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001053 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001054 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001055 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001056 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1057 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001058 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1059 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1061 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1062 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1063 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1064 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1065 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1066 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1067 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1068 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1069 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001071 {
1072 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1073 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001074 .info = alc_ch_mode_info,
1075 .get = alc_ch_mode_get,
1076 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001077 },
1078 { } /* end */
1079};
1080
1081/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001082static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001083 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1084 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1085 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1086 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1087 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1088 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1089 {
1090 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1091 /* The multiple "Capture Source" controls confuse alsamixer
1092 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001093 */
1094 /* .name = "Capture Source", */
1095 .name = "Input Source",
1096 .count = 3,
1097 .info = alc_mux_enum_info,
1098 .get = alc_mux_enum_get,
1099 .put = alc_mux_enum_put,
1100 },
1101 { } /* end */
1102};
1103
1104/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001105static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001106 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1107 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1108 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1109 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 {
1111 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1112 /* The multiple "Capture Source" controls confuse alsamixer
1113 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 */
1115 /* .name = "Capture Source", */
1116 .name = "Input Source",
1117 .count = 2,
1118 .info = alc_mux_enum_info,
1119 .get = alc_mux_enum_get,
1120 .put = alc_mux_enum_put,
1121 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 { } /* end */
1123};
1124
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001125
1126
1127/*
1128 * ALC880 5-stack model
1129 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001130 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1131 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001132 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1133 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1134 */
1135
1136/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001137static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001138 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001139 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 { } /* end */
1141};
1142
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001143/* channel source setting (6/8 channel selection for 5-stack) */
1144/* 6ch mode */
1145static struct hda_verb alc880_fivestack_ch6_init[] = {
1146 /* set line-in to input, mute it */
1147 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1148 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001149 { } /* end */
1150};
1151
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001152/* 8ch mode */
1153static struct hda_verb alc880_fivestack_ch8_init[] = {
1154 /* set line-in to output, unmute it */
1155 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1156 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1157 { } /* end */
1158};
1159
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001160static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001161 { 6, alc880_fivestack_ch6_init },
1162 { 8, alc880_fivestack_ch8_init },
1163};
1164
1165
1166/*
1167 * ALC880 6-stack model
1168 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001169 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1170 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001171 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1172 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1173 */
1174
1175static hda_nid_t alc880_6st_dac_nids[4] = {
1176 /* front, rear, clfe, rear_surr */
1177 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001178};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001179
1180static struct hda_input_mux alc880_6stack_capture_source = {
1181 .num_items = 4,
1182 .items = {
1183 { "Mic", 0x0 },
1184 { "Front Mic", 0x1 },
1185 { "Line", 0x2 },
1186 { "CD", 0x4 },
1187 },
1188};
1189
1190/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001191static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001192 { 8, NULL },
1193};
1194
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001195static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001196 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001197 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001198 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001199 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001200 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1201 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001202 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1203 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001204 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001205 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001206 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1207 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1208 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1209 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1210 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1211 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1212 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1213 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1214 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1215 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001216 {
1217 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1218 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001219 .info = alc_ch_mode_info,
1220 .get = alc_ch_mode_get,
1221 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001222 },
1223 { } /* end */
1224};
1225
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001226
1227/*
1228 * ALC880 W810 model
1229 *
1230 * W810 has rear IO for:
1231 * Front (DAC 02)
1232 * Surround (DAC 03)
1233 * Center/LFE (DAC 04)
1234 * Digital out (06)
1235 *
1236 * The system also has a pair of internal speakers, and a headphone jack.
1237 * These are both connected to Line2 on the codec, hence to DAC 02.
1238 *
1239 * There is a variable resistor to control the speaker or headphone
1240 * volume. This is a hardware-only device without a software API.
1241 *
1242 * Plugging headphones in will disable the internal speakers. This is
1243 * implemented in hardware, not via the driver using jack sense. In
1244 * a similar fashion, plugging into the rear socket marked "front" will
1245 * disable both the speakers and headphones.
1246 *
1247 * For input, there's a microphone jack, and an "audio in" jack.
1248 * These may not do anything useful with this driver yet, because I
1249 * haven't setup any initialization verbs for these yet...
1250 */
1251
1252static hda_nid_t alc880_w810_dac_nids[3] = {
1253 /* front, rear/surround, clfe */
1254 0x02, 0x03, 0x04
1255};
1256
1257/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001258static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001259 { 6, NULL }
1260};
1261
1262/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001263static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001264 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001265 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001266 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001267 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001268 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1269 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001270 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1271 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001272 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1273 { } /* end */
1274};
1275
1276
1277/*
1278 * Z710V model
1279 *
1280 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001281 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1282 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001283 */
1284
1285static hda_nid_t alc880_z71v_dac_nids[1] = {
1286 0x02
1287};
1288#define ALC880_Z71V_HP_DAC 0x03
1289
1290/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001291static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001292 { 2, NULL }
1293};
1294
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001295static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001296 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001297 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001298 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001299 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001300 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1301 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1302 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1303 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1304 { } /* end */
1305};
1306
1307
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001308/*
1309 * ALC880 F1734 model
1310 *
1311 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1312 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1313 */
1314
1315static hda_nid_t alc880_f1734_dac_nids[1] = {
1316 0x03
1317};
1318#define ALC880_F1734_HP_DAC 0x02
1319
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001320static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001321 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001322 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001323 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1324 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001325 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1326 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001327 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1328 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001329 { } /* end */
1330};
1331
Takashi Iwai937b4162008-02-11 14:52:36 +01001332static struct hda_input_mux alc880_f1734_capture_source = {
1333 .num_items = 2,
1334 .items = {
1335 { "Mic", 0x1 },
1336 { "CD", 0x4 },
1337 },
1338};
1339
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001340
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001341/*
1342 * ALC880 ASUS model
1343 *
1344 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1345 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1346 * Mic = 0x18, Line = 0x1a
1347 */
1348
1349#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1350#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1351
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001352static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001353 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001354 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001355 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001356 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001357 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1358 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001359 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1360 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001361 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1362 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1363 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1364 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1365 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1366 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001367 {
1368 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1369 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001370 .info = alc_ch_mode_info,
1371 .get = alc_ch_mode_get,
1372 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001373 },
1374 { } /* end */
1375};
1376
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001377/*
1378 * ALC880 ASUS W1V model
1379 *
1380 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1381 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1382 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1383 */
1384
1385/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001386static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001387 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1388 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001389 { } /* end */
1390};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001391
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001392/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001393static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001394 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1395 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1396 { } /* end */
1397};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001398
Kailang Yangdf694da2005-12-05 19:42:22 +01001399/* TCL S700 */
1400static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1401 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1402 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1403 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1404 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1405 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1406 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1407 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1408 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1409 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1410 {
1411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1412 /* The multiple "Capture Source" controls confuse alsamixer
1413 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001414 */
1415 /* .name = "Capture Source", */
1416 .name = "Input Source",
1417 .count = 1,
1418 .info = alc_mux_enum_info,
1419 .get = alc_mux_enum_get,
1420 .put = alc_mux_enum_put,
1421 },
1422 { } /* end */
1423};
1424
Kailang Yangccc656c2006-10-17 12:32:26 +02001425/* Uniwill */
1426static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001427 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1428 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1429 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1430 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001431 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1432 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1433 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1434 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1435 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1436 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1437 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1438 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1439 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1440 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1441 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1442 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1443 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1444 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1445 {
1446 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1447 .name = "Channel Mode",
1448 .info = alc_ch_mode_info,
1449 .get = alc_ch_mode_get,
1450 .put = alc_ch_mode_put,
1451 },
1452 { } /* end */
1453};
1454
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001455static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1456 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1457 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1458 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1459 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1460 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1461 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1462 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1463 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1464 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1465 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1466 { } /* end */
1467};
1468
Kailang Yangccc656c2006-10-17 12:32:26 +02001469static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001470 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1471 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1472 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1473 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001474 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1475 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1476 { } /* end */
1477};
1478
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001480 * virtual master controls
1481 */
1482
1483/*
1484 * slave controls for virtual master
1485 */
1486static const char *alc_slave_vols[] = {
1487 "Front Playback Volume",
1488 "Surround Playback Volume",
1489 "Center Playback Volume",
1490 "LFE Playback Volume",
1491 "Side Playback Volume",
1492 "Headphone Playback Volume",
1493 "Speaker Playback Volume",
1494 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001495 "Line-Out Playback Volume",
1496 NULL,
1497};
1498
1499static const char *alc_slave_sws[] = {
1500 "Front Playback Switch",
1501 "Surround Playback Switch",
1502 "Center Playback Switch",
1503 "LFE Playback Switch",
1504 "Side Playback Switch",
1505 "Headphone Playback Switch",
1506 "Speaker Playback Switch",
1507 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001508 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001509 NULL,
1510};
1511
1512/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001513 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 */
1515static int alc_build_controls(struct hda_codec *codec)
1516{
1517 struct alc_spec *spec = codec->spec;
1518 int err;
1519 int i;
1520
1521 for (i = 0; i < spec->num_mixers; i++) {
1522 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1523 if (err < 0)
1524 return err;
1525 }
1526
1527 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001528 err = snd_hda_create_spdif_out_ctls(codec,
1529 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 if (err < 0)
1531 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001532 err = snd_hda_create_spdif_share_sw(codec,
1533 &spec->multiout);
1534 if (err < 0)
1535 return err;
1536 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 }
1538 if (spec->dig_in_nid) {
1539 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1540 if (err < 0)
1541 return err;
1542 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001543
1544 /* if we have no master control, let's create it */
1545 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001546 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001547 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001548 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001549 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001550 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001551 if (err < 0)
1552 return err;
1553 }
1554 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1555 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1556 NULL, alc_slave_sws);
1557 if (err < 0)
1558 return err;
1559 }
1560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 return 0;
1562}
1563
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565/*
1566 * initialize the codec volumes, etc
1567 */
1568
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001569/*
1570 * generic initialization of ADC, input mixers and output mixers
1571 */
1572static struct hda_verb alc880_volume_init_verbs[] = {
1573 /*
1574 * Unmute ADC0-2 and set the default input to mic-in
1575 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001576 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001577 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001578 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001579 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001580 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001581 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001583 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1584 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001585 * Note: PASD motherboards uses the Line In 2 as the input for front
1586 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001588 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001589 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1590 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1591 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1592 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1593 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1594 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1595 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001597 /*
1598 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001600 /* set vol=0 to output mixers */
1601 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1602 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1603 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1604 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1605 /* set up input amps for analog loopback */
1606 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001607 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1608 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001609 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1610 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001611 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1612 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001613 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1614 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
1616 { }
1617};
1618
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001619/*
1620 * 3-stack pin configuration:
1621 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1622 */
1623static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1624 /*
1625 * preset connection lists of input pins
1626 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1627 */
1628 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1629 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1630 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1631
1632 /*
1633 * Set pin mode and muting
1634 */
1635 /* set front pin widgets 0x14 for output */
1636 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1637 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1638 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1639 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1640 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1641 /* Mic2 (as headphone out) for HP output */
1642 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1643 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1644 /* Line In pin widget for input */
1645 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1646 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1647 /* Line2 (as front mic) pin widget for input and vref at 80% */
1648 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1649 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1650 /* CD pin widget for input */
1651 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1652
1653 { }
1654};
1655
1656/*
1657 * 5-stack pin configuration:
1658 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1659 * line-in/side = 0x1a, f-mic = 0x1b
1660 */
1661static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1662 /*
1663 * preset connection lists of input pins
1664 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1665 */
1666 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1667 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1668
1669 /*
1670 * Set pin mode and muting
1671 */
1672 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001673 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1674 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1675 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1676 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001677 /* unmute pins for output (no gain on this amp) */
1678 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1679 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1680 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1681 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001684 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001685 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1686 /* Mic2 (as headphone out) for HP output */
1687 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001688 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001689 /* Line In pin widget for input */
1690 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1691 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1692 /* Line2 (as front mic) pin widget for input and vref at 80% */
1693 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1694 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1695 /* CD pin widget for input */
1696 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
1698 { }
1699};
1700
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001701/*
1702 * W810 pin configuration:
1703 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1704 */
1705static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 /* hphone/speaker input selector: front DAC */
1707 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1708
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001709 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1710 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1711 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1712 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1713 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1714 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1715
1716 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001717 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 { }
1720};
1721
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001722/*
1723 * Z71V pin configuration:
1724 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1725 */
1726static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001727 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001728 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001729 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001730 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001731
Takashi Iwai16ded522005-06-10 19:58:24 +02001732 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001733 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001734 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001735 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001736
1737 { }
1738};
1739
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001740/*
1741 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001742 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1743 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001744 */
1745static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1746 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1747
Takashi Iwai16ded522005-06-10 19:58:24 +02001748 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001749 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001750 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001751 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001752 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001753 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001754 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001755 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1756
Takashi Iwai16ded522005-06-10 19:58:24 +02001757 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001758 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001759 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001760 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001761 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001762 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001763 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001764 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001765 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1766
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001767 { }
1768};
Takashi Iwai16ded522005-06-10 19:58:24 +02001769
Kailang Yangccc656c2006-10-17 12:32:26 +02001770/*
1771 * Uniwill pin configuration:
1772 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1773 * line = 0x1a
1774 */
1775static struct hda_verb alc880_uniwill_init_verbs[] = {
1776 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1777
1778 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1779 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1780 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1781 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1782 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1783 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1784 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1785 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1786 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1787 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1788 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1789 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1790 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1791 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1792
1793 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1794 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1795 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1796 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1797 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1798 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1799 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1800 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1801 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1802
1803 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1804 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1805
1806 { }
1807};
1808
1809/*
1810* Uniwill P53
1811* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1812 */
1813static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1814 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1815
1816 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1817 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1818 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1819 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1820 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1821 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1822 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1823 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1824 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1825 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1826 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1827 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1828
1829 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1830 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1831 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1832 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1833 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1835
1836 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1837 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1838
1839 { }
1840};
1841
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001842static struct hda_verb alc880_beep_init_verbs[] = {
1843 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1844 { }
1845};
1846
Kailang Yangccc656c2006-10-17 12:32:26 +02001847/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001848static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001849{
1850 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001851 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001852
1853 present = snd_hda_codec_read(codec, 0x14, 0,
1854 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001855 bits = present ? HDA_AMP_MUTE : 0;
1856 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1857 HDA_AMP_MUTE, bits);
1858 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1859 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001860}
1861
1862/* auto-toggle front mic */
1863static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1864{
1865 unsigned int present;
1866 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001867
1868 present = snd_hda_codec_read(codec, 0x18, 0,
1869 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001870 bits = present ? HDA_AMP_MUTE : 0;
1871 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001872}
1873
1874static void alc880_uniwill_automute(struct hda_codec *codec)
1875{
1876 alc880_uniwill_hp_automute(codec);
1877 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001878}
1879
1880static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1881 unsigned int res)
1882{
1883 /* Looks like the unsol event is incompatible with the standard
1884 * definition. 4bit tag is placed at 28 bit!
1885 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001886 switch (res >> 28) {
1887 case ALC880_HP_EVENT:
1888 alc880_uniwill_hp_automute(codec);
1889 break;
1890 case ALC880_MIC_EVENT:
1891 alc880_uniwill_mic_automute(codec);
1892 break;
1893 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001894}
1895
1896static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1897{
1898 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001899 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001900
1901 present = snd_hda_codec_read(codec, 0x14, 0,
1902 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001903 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02001904 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001905}
1906
1907static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1908{
1909 unsigned int present;
1910
1911 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001912 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1913 present &= HDA_AMP_VOLMASK;
1914 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1915 HDA_AMP_VOLMASK, present);
1916 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1917 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001918}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001919
Kailang Yangccc656c2006-10-17 12:32:26 +02001920static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1921 unsigned int res)
1922{
1923 /* Looks like the unsol event is incompatible with the standard
1924 * definition. 4bit tag is placed at 28 bit!
1925 */
1926 if ((res >> 28) == ALC880_HP_EVENT)
1927 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001928 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001929 alc880_uniwill_p53_dcvol_automute(codec);
1930}
1931
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001932/*
1933 * F1734 pin configuration:
1934 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1935 */
1936static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01001937 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001938 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1939 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1940 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1941 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1942
1943 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1944 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1945 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1946 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1947
1948 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1949 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01001950 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001951 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1952 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1953 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1954 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1955 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1956 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001957
Takashi Iwai937b4162008-02-11 14:52:36 +01001958 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
1959 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
1960
Takashi Iwai16ded522005-06-10 19:58:24 +02001961 { }
1962};
1963
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001964/*
1965 * ASUS pin configuration:
1966 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1967 */
1968static struct hda_verb alc880_pin_asus_init_verbs[] = {
1969 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1970 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1971 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1972 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1973
1974 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1976 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1977 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1978 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1979 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1980 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1981 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1982
1983 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1984 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1985 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1986 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1987 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1988 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1989 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1990 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1991 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1992
1993 { }
1994};
1995
1996/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001997#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1998#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001999
Kailang Yangdf694da2005-12-05 19:42:22 +01002000/* Clevo m520g init */
2001static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2002 /* headphone output */
2003 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2004 /* line-out */
2005 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2006 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2007 /* Line-in */
2008 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2009 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2010 /* CD */
2011 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2012 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2013 /* Mic1 (rear panel) */
2014 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2015 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2016 /* Mic2 (front panel) */
2017 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2018 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2019 /* headphone */
2020 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2021 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2022 /* change to EAPD mode */
2023 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2024 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2025
2026 { }
2027};
2028
2029static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002030 /* change to EAPD mode */
2031 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2032 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2033
Kailang Yangdf694da2005-12-05 19:42:22 +01002034 /* Headphone output */
2035 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2036 /* Front output*/
2037 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2038 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2039
2040 /* Line In pin widget for input */
2041 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2042 /* CD pin widget for input */
2043 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2044 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2045 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2046
2047 /* change to EAPD mode */
2048 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2049 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2050
2051 { }
2052};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002053
2054/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002055 * LG m1 express dual
2056 *
2057 * Pin assignment:
2058 * Rear Line-In/Out (blue): 0x14
2059 * Build-in Mic-In: 0x15
2060 * Speaker-out: 0x17
2061 * HP-Out (green): 0x1b
2062 * Mic-In/Out (red): 0x19
2063 * SPDIF-Out: 0x1e
2064 */
2065
2066/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2067static hda_nid_t alc880_lg_dac_nids[3] = {
2068 0x05, 0x02, 0x03
2069};
2070
2071/* seems analog CD is not working */
2072static struct hda_input_mux alc880_lg_capture_source = {
2073 .num_items = 3,
2074 .items = {
2075 { "Mic", 0x1 },
2076 { "Line", 0x5 },
2077 { "Internal Mic", 0x6 },
2078 },
2079};
2080
2081/* 2,4,6 channel modes */
2082static struct hda_verb alc880_lg_ch2_init[] = {
2083 /* set line-in and mic-in to input */
2084 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2085 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2086 { }
2087};
2088
2089static struct hda_verb alc880_lg_ch4_init[] = {
2090 /* set line-in to out and mic-in to input */
2091 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2092 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2093 { }
2094};
2095
2096static struct hda_verb alc880_lg_ch6_init[] = {
2097 /* set line-in and mic-in to output */
2098 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2099 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2100 { }
2101};
2102
2103static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2104 { 2, alc880_lg_ch2_init },
2105 { 4, alc880_lg_ch4_init },
2106 { 6, alc880_lg_ch6_init },
2107};
2108
2109static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002110 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2111 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002112 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2113 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2114 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2115 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2116 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2117 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2118 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2119 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2120 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2121 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2122 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2123 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2124 {
2125 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2126 .name = "Channel Mode",
2127 .info = alc_ch_mode_info,
2128 .get = alc_ch_mode_get,
2129 .put = alc_ch_mode_put,
2130 },
2131 { } /* end */
2132};
2133
2134static struct hda_verb alc880_lg_init_verbs[] = {
2135 /* set capture source to mic-in */
2136 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2137 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2138 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2139 /* mute all amp mixer inputs */
2140 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002141 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2142 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002143 /* line-in to input */
2144 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2145 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2146 /* built-in mic */
2147 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2148 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2149 /* speaker-out */
2150 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2151 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2152 /* mic-in to input */
2153 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2154 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2155 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2156 /* HP-out */
2157 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2158 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2159 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2160 /* jack sense */
2161 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2162 { }
2163};
2164
2165/* toggle speaker-output according to the hp-jack state */
2166static void alc880_lg_automute(struct hda_codec *codec)
2167{
2168 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002169 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002170
2171 present = snd_hda_codec_read(codec, 0x1b, 0,
2172 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002173 bits = present ? HDA_AMP_MUTE : 0;
2174 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2175 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002176}
2177
2178static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2179{
2180 /* Looks like the unsol event is incompatible with the standard
2181 * definition. 4bit tag is placed at 28 bit!
2182 */
2183 if ((res >> 28) == 0x01)
2184 alc880_lg_automute(codec);
2185}
2186
2187/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002188 * LG LW20
2189 *
2190 * Pin assignment:
2191 * Speaker-out: 0x14
2192 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002193 * Built-in Mic-In: 0x19
2194 * Line-In: 0x1b
2195 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002196 * SPDIF-Out: 0x1e
2197 */
2198
Takashi Iwaid6815182006-03-23 16:06:23 +01002199static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002200 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002201 .items = {
2202 { "Mic", 0x0 },
2203 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002204 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002205 },
2206};
2207
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002208#define alc880_lg_lw_modes alc880_threestack_modes
2209
Takashi Iwaid6815182006-03-23 16:06:23 +01002210static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002211 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2212 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2213 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2214 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2215 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2216 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2217 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2218 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2219 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2220 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002221 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2222 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2223 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2224 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002225 {
2226 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2227 .name = "Channel Mode",
2228 .info = alc_ch_mode_info,
2229 .get = alc_ch_mode_get,
2230 .put = alc_ch_mode_put,
2231 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002232 { } /* end */
2233};
2234
2235static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002236 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2237 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2238 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2239
Takashi Iwaid6815182006-03-23 16:06:23 +01002240 /* set capture source to mic-in */
2241 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2242 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2243 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002244 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002245 /* speaker-out */
2246 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2247 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2248 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002249 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2250 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2251 /* mic-in to input */
2252 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2253 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2254 /* built-in mic */
2255 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2256 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2257 /* jack sense */
2258 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2259 { }
2260};
2261
2262/* toggle speaker-output according to the hp-jack state */
2263static void alc880_lg_lw_automute(struct hda_codec *codec)
2264{
2265 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002266 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002267
2268 present = snd_hda_codec_read(codec, 0x1b, 0,
2269 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002270 bits = present ? HDA_AMP_MUTE : 0;
2271 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2272 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002273}
2274
2275static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2276{
2277 /* Looks like the unsol event is incompatible with the standard
2278 * definition. 4bit tag is placed at 28 bit!
2279 */
2280 if ((res >> 28) == 0x01)
2281 alc880_lg_lw_automute(codec);
2282}
2283
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002284static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2285 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2286 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2288 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2289 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2290 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2291 { } /* end */
2292};
2293
2294static struct hda_input_mux alc880_medion_rim_capture_source = {
2295 .num_items = 2,
2296 .items = {
2297 { "Mic", 0x0 },
2298 { "Internal Mic", 0x1 },
2299 },
2300};
2301
2302static struct hda_verb alc880_medion_rim_init_verbs[] = {
2303 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2304
2305 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2306 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2307
2308 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2309 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2310 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2311 /* Mic2 (as headphone out) for HP output */
2312 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2313 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2314 /* Internal Speaker */
2315 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2316 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2317
2318 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2319 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2320
2321 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2322 { }
2323};
2324
2325/* toggle speaker-output according to the hp-jack state */
2326static void alc880_medion_rim_automute(struct hda_codec *codec)
2327{
2328 unsigned int present;
2329 unsigned char bits;
2330
2331 present = snd_hda_codec_read(codec, 0x14, 0,
2332 AC_VERB_GET_PIN_SENSE, 0)
2333 & AC_PINSENSE_PRESENCE;
2334 bits = present ? HDA_AMP_MUTE : 0;
2335 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2336 HDA_AMP_MUTE, bits);
2337 if (present)
2338 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2339 else
2340 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2341}
2342
2343static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2344 unsigned int res)
2345{
2346 /* Looks like the unsol event is incompatible with the standard
2347 * definition. 4bit tag is placed at 28 bit!
2348 */
2349 if ((res >> 28) == ALC880_HP_EVENT)
2350 alc880_medion_rim_automute(codec);
2351}
2352
Takashi Iwaicb53c622007-08-10 17:21:45 +02002353#ifdef CONFIG_SND_HDA_POWER_SAVE
2354static struct hda_amp_list alc880_loopbacks[] = {
2355 { 0x0b, HDA_INPUT, 0 },
2356 { 0x0b, HDA_INPUT, 1 },
2357 { 0x0b, HDA_INPUT, 2 },
2358 { 0x0b, HDA_INPUT, 3 },
2359 { 0x0b, HDA_INPUT, 4 },
2360 { } /* end */
2361};
2362
2363static struct hda_amp_list alc880_lg_loopbacks[] = {
2364 { 0x0b, HDA_INPUT, 1 },
2365 { 0x0b, HDA_INPUT, 6 },
2366 { 0x0b, HDA_INPUT, 7 },
2367 { } /* end */
2368};
2369#endif
2370
Takashi Iwaid6815182006-03-23 16:06:23 +01002371/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002372 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002373 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002374
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375static int alc_init(struct hda_codec *codec)
2376{
2377 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002378 unsigned int i;
2379
2380 for (i = 0; i < spec->num_init_verbs; i++)
2381 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002382
2383 if (spec->init_hook)
2384 spec->init_hook(codec);
2385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 return 0;
2387}
2388
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002389static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2390{
2391 struct alc_spec *spec = codec->spec;
2392
2393 if (spec->unsol_event)
2394 spec->unsol_event(codec, res);
2395}
2396
Takashi Iwaicb53c622007-08-10 17:21:45 +02002397#ifdef CONFIG_SND_HDA_POWER_SAVE
2398static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2399{
2400 struct alc_spec *spec = codec->spec;
2401 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2402}
2403#endif
2404
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405/*
2406 * Analog playback callbacks
2407 */
2408static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2409 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002410 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411{
2412 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002413 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2414 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415}
2416
2417static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2418 struct hda_codec *codec,
2419 unsigned int stream_tag,
2420 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002421 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422{
2423 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002424 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2425 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426}
2427
2428static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2429 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002430 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431{
2432 struct alc_spec *spec = codec->spec;
2433 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2434}
2435
2436/*
2437 * Digital out
2438 */
2439static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2440 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002441 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442{
2443 struct alc_spec *spec = codec->spec;
2444 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2445}
2446
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002447static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2448 struct hda_codec *codec,
2449 unsigned int stream_tag,
2450 unsigned int format,
2451 struct snd_pcm_substream *substream)
2452{
2453 struct alc_spec *spec = codec->spec;
2454 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2455 stream_tag, format, substream);
2456}
2457
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2459 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002460 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461{
2462 struct alc_spec *spec = codec->spec;
2463 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2464}
2465
2466/*
2467 * Analog capture
2468 */
Takashi Iwai63300792008-01-24 15:31:36 +01002469static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 struct hda_codec *codec,
2471 unsigned int stream_tag,
2472 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002473 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474{
2475 struct alc_spec *spec = codec->spec;
2476
Takashi Iwai63300792008-01-24 15:31:36 +01002477 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 stream_tag, 0, format);
2479 return 0;
2480}
2481
Takashi Iwai63300792008-01-24 15:31:36 +01002482static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002484 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485{
2486 struct alc_spec *spec = codec->spec;
2487
Takashi Iwai888afa12008-03-18 09:57:50 +01002488 snd_hda_codec_cleanup_stream(codec,
2489 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 return 0;
2491}
2492
2493
2494/*
2495 */
2496static struct hda_pcm_stream alc880_pcm_analog_playback = {
2497 .substreams = 1,
2498 .channels_min = 2,
2499 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002500 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 .ops = {
2502 .open = alc880_playback_pcm_open,
2503 .prepare = alc880_playback_pcm_prepare,
2504 .cleanup = alc880_playback_pcm_cleanup
2505 },
2506};
2507
2508static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002509 .substreams = 1,
2510 .channels_min = 2,
2511 .channels_max = 2,
2512 /* NID is set in alc_build_pcms */
2513};
2514
2515static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2516 .substreams = 1,
2517 .channels_min = 2,
2518 .channels_max = 2,
2519 /* NID is set in alc_build_pcms */
2520};
2521
2522static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2523 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 .channels_min = 2,
2525 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002526 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002528 .prepare = alc880_alt_capture_pcm_prepare,
2529 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 },
2531};
2532
2533static struct hda_pcm_stream alc880_pcm_digital_playback = {
2534 .substreams = 1,
2535 .channels_min = 2,
2536 .channels_max = 2,
2537 /* NID is set in alc_build_pcms */
2538 .ops = {
2539 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002540 .close = alc880_dig_playback_pcm_close,
2541 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 },
2543};
2544
2545static struct hda_pcm_stream alc880_pcm_digital_capture = {
2546 .substreams = 1,
2547 .channels_min = 2,
2548 .channels_max = 2,
2549 /* NID is set in alc_build_pcms */
2550};
2551
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002552/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002553static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002554 .substreams = 0,
2555 .channels_min = 0,
2556 .channels_max = 0,
2557};
2558
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559static int alc_build_pcms(struct hda_codec *codec)
2560{
2561 struct alc_spec *spec = codec->spec;
2562 struct hda_pcm *info = spec->pcm_rec;
2563 int i;
2564
2565 codec->num_pcms = 1;
2566 codec->pcm_info = info;
2567
2568 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002569 if (spec->stream_analog_playback) {
2570 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2571 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2572 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2573 }
2574 if (spec->stream_analog_capture) {
2575 snd_assert(spec->adc_nids, return -EINVAL);
2576 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2577 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
Takashi Iwai4a471b72005-12-07 13:56:29 +01002580 if (spec->channel_mode) {
2581 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2582 for (i = 0; i < spec->num_channel_mode; i++) {
2583 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2584 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 }
2587 }
2588
Takashi Iwaie08a0072006-09-07 17:52:14 +02002589 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002591 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002592 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002594 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002595 if (spec->multiout.dig_out_nid &&
2596 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2598 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2599 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002600 if (spec->dig_in_nid &&
2601 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2603 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2604 }
2605 }
2606
Takashi Iwaie08a0072006-09-07 17:52:14 +02002607 /* If the use of more than one ADC is requested for the current
2608 * model, configure a second analog capture-only PCM.
2609 */
2610 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002611 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2612 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002613 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002614 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002615 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002616 if (spec->alt_dac_nid) {
2617 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2618 *spec->stream_analog_alt_playback;
2619 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2620 spec->alt_dac_nid;
2621 } else {
2622 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2623 alc_pcm_null_stream;
2624 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2625 }
2626 if (spec->num_adc_nids > 1) {
2627 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2628 *spec->stream_analog_alt_capture;
2629 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2630 spec->adc_nids[1];
2631 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2632 spec->num_adc_nids - 1;
2633 } else {
2634 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2635 alc_pcm_null_stream;
2636 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002637 }
2638 }
2639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 return 0;
2641}
2642
2643static void alc_free(struct hda_codec *codec)
2644{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002645 struct alc_spec *spec = codec->spec;
2646 unsigned int i;
2647
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002648 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002649 return;
2650
2651 if (spec->kctl_alloc) {
2652 for (i = 0; i < spec->num_kctl_used; i++)
2653 kfree(spec->kctl_alloc[i].name);
2654 kfree(spec->kctl_alloc);
2655 }
2656 kfree(spec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02002657 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658}
2659
2660/*
2661 */
2662static struct hda_codec_ops alc_patch_ops = {
2663 .build_controls = alc_build_controls,
2664 .build_pcms = alc_build_pcms,
2665 .init = alc_init,
2666 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002667 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002668#ifdef CONFIG_SND_HDA_POWER_SAVE
2669 .check_power_status = alc_check_power_status,
2670#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671};
2672
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002673
2674/*
2675 * Test configuration for debugging
2676 *
2677 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2678 * enum controls.
2679 */
2680#ifdef CONFIG_SND_DEBUG
2681static hda_nid_t alc880_test_dac_nids[4] = {
2682 0x02, 0x03, 0x04, 0x05
2683};
2684
2685static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002686 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002687 .items = {
2688 { "In-1", 0x0 },
2689 { "In-2", 0x1 },
2690 { "In-3", 0x2 },
2691 { "In-4", 0x3 },
2692 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002693 { "Front", 0x5 },
2694 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002695 },
2696};
2697
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002698static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002699 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002700 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002701 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002702 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002703};
2704
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002705static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2706 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002707{
2708 static char *texts[] = {
2709 "N/A", "Line Out", "HP Out",
2710 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2711 };
2712 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2713 uinfo->count = 1;
2714 uinfo->value.enumerated.items = 8;
2715 if (uinfo->value.enumerated.item >= 8)
2716 uinfo->value.enumerated.item = 7;
2717 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2718 return 0;
2719}
2720
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002721static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2722 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002723{
2724 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2725 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2726 unsigned int pin_ctl, item = 0;
2727
2728 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2729 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2730 if (pin_ctl & AC_PINCTL_OUT_EN) {
2731 if (pin_ctl & AC_PINCTL_HP_EN)
2732 item = 2;
2733 else
2734 item = 1;
2735 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2736 switch (pin_ctl & AC_PINCTL_VREFEN) {
2737 case AC_PINCTL_VREF_HIZ: item = 3; break;
2738 case AC_PINCTL_VREF_50: item = 4; break;
2739 case AC_PINCTL_VREF_GRD: item = 5; break;
2740 case AC_PINCTL_VREF_80: item = 6; break;
2741 case AC_PINCTL_VREF_100: item = 7; break;
2742 }
2743 }
2744 ucontrol->value.enumerated.item[0] = item;
2745 return 0;
2746}
2747
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002748static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2749 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002750{
2751 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2752 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2753 static unsigned int ctls[] = {
2754 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2755 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2756 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2757 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2758 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2759 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2760 };
2761 unsigned int old_ctl, new_ctl;
2762
2763 old_ctl = snd_hda_codec_read(codec, nid, 0,
2764 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2765 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2766 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002767 int val;
2768 snd_hda_codec_write_cache(codec, nid, 0,
2769 AC_VERB_SET_PIN_WIDGET_CONTROL,
2770 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002771 val = ucontrol->value.enumerated.item[0] >= 3 ?
2772 HDA_AMP_MUTE : 0;
2773 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2774 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002775 return 1;
2776 }
2777 return 0;
2778}
2779
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002780static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2781 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002782{
2783 static char *texts[] = {
2784 "Front", "Surround", "CLFE", "Side"
2785 };
2786 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2787 uinfo->count = 1;
2788 uinfo->value.enumerated.items = 4;
2789 if (uinfo->value.enumerated.item >= 4)
2790 uinfo->value.enumerated.item = 3;
2791 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2792 return 0;
2793}
2794
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002795static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2796 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002797{
2798 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2799 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2800 unsigned int sel;
2801
2802 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2803 ucontrol->value.enumerated.item[0] = sel & 3;
2804 return 0;
2805}
2806
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002807static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2808 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002809{
2810 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2811 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2812 unsigned int sel;
2813
2814 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2815 if (ucontrol->value.enumerated.item[0] != sel) {
2816 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002817 snd_hda_codec_write_cache(codec, nid, 0,
2818 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002819 return 1;
2820 }
2821 return 0;
2822}
2823
2824#define PIN_CTL_TEST(xname,nid) { \
2825 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2826 .name = xname, \
2827 .info = alc_test_pin_ctl_info, \
2828 .get = alc_test_pin_ctl_get, \
2829 .put = alc_test_pin_ctl_put, \
2830 .private_value = nid \
2831 }
2832
2833#define PIN_SRC_TEST(xname,nid) { \
2834 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2835 .name = xname, \
2836 .info = alc_test_pin_src_info, \
2837 .get = alc_test_pin_src_get, \
2838 .put = alc_test_pin_src_put, \
2839 .private_value = nid \
2840 }
2841
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002842static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002843 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2844 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2845 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2846 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002847 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2848 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2849 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2850 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002851 PIN_CTL_TEST("Front Pin Mode", 0x14),
2852 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2853 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2854 PIN_CTL_TEST("Side Pin Mode", 0x17),
2855 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2856 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2857 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2858 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2859 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2860 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2861 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2862 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2863 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2864 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2865 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2866 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2867 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2868 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2869 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2870 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2871 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2872 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002873 {
2874 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2875 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002876 .info = alc_ch_mode_info,
2877 .get = alc_ch_mode_get,
2878 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002879 },
2880 { } /* end */
2881};
2882
2883static struct hda_verb alc880_test_init_verbs[] = {
2884 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002885 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2886 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2887 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2888 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2889 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2890 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2891 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2892 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002893 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002894 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2895 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2896 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2897 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002898 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002899 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2900 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2901 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2902 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002903 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002904 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2905 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2906 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2907 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002908 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002909 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2910 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002911 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2912 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2913 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002914 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002915 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2916 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2917 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2918 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002919 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002920 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002921 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002922 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002923 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002924 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002925 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002926 /* Analog input/passthru */
2927 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2928 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2929 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2930 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2931 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002932 { }
2933};
2934#endif
2935
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936/*
2937 */
2938
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002939static const char *alc880_models[ALC880_MODEL_LAST] = {
2940 [ALC880_3ST] = "3stack",
2941 [ALC880_TCL_S700] = "tcl",
2942 [ALC880_3ST_DIG] = "3stack-digout",
2943 [ALC880_CLEVO] = "clevo",
2944 [ALC880_5ST] = "5stack",
2945 [ALC880_5ST_DIG] = "5stack-digout",
2946 [ALC880_W810] = "w810",
2947 [ALC880_Z71V] = "z71v",
2948 [ALC880_6ST] = "6stack",
2949 [ALC880_6ST_DIG] = "6stack-digout",
2950 [ALC880_ASUS] = "asus",
2951 [ALC880_ASUS_W1V] = "asus-w1v",
2952 [ALC880_ASUS_DIG] = "asus-dig",
2953 [ALC880_ASUS_DIG2] = "asus-dig2",
2954 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002955 [ALC880_UNIWILL_P53] = "uniwill-p53",
2956 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002957 [ALC880_F1734] = "F1734",
2958 [ALC880_LG] = "lg",
2959 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002960 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002961#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002962 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002963#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002964 [ALC880_AUTO] = "auto",
2965};
2966
2967static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002968 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002969 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2970 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2971 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2972 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2973 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2974 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2975 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2976 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002977 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2978 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002979 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2980 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2981 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2982 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2983 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2984 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2985 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2986 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2987 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2988 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02002989 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002990 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2991 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2992 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002993 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002994 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002995 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2996 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002997 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2998 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002999 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3000 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3001 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3002 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003003 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3004 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003005 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003006 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003007 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003008 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003009 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3010 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003011 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003012 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003013 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003014 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003015 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003016 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003017 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003018 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003019 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3020 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003021 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003022 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3023 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3024 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3025 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003026 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3027 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003028 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003029 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003030 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3031 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003032 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3033 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3034 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003035 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3036 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3037 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 {}
3039};
3040
Takashi Iwai16ded522005-06-10 19:58:24 +02003041/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003042 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003043 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003044static struct alc_config_preset alc880_presets[] = {
3045 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003046 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003047 .init_verbs = { alc880_volume_init_verbs,
3048 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003049 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003050 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003051 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3052 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003053 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003054 .input_mux = &alc880_capture_source,
3055 },
3056 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003057 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003058 .init_verbs = { alc880_volume_init_verbs,
3059 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003060 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003061 .dac_nids = alc880_dac_nids,
3062 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003063 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3064 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003065 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003066 .input_mux = &alc880_capture_source,
3067 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003068 [ALC880_TCL_S700] = {
3069 .mixers = { alc880_tcl_s700_mixer },
3070 .init_verbs = { alc880_volume_init_verbs,
3071 alc880_pin_tcl_S700_init_verbs,
3072 alc880_gpio2_init_verbs },
3073 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3074 .dac_nids = alc880_dac_nids,
3075 .hp_nid = 0x03,
3076 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3077 .channel_mode = alc880_2_jack_modes,
3078 .input_mux = &alc880_capture_source,
3079 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003080 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003081 .mixers = { alc880_three_stack_mixer,
3082 alc880_five_stack_mixer},
3083 .init_verbs = { alc880_volume_init_verbs,
3084 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003085 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3086 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003087 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3088 .channel_mode = alc880_fivestack_modes,
3089 .input_mux = &alc880_capture_source,
3090 },
3091 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003092 .mixers = { alc880_three_stack_mixer,
3093 alc880_five_stack_mixer },
3094 .init_verbs = { alc880_volume_init_verbs,
3095 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003096 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3097 .dac_nids = alc880_dac_nids,
3098 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003099 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3100 .channel_mode = alc880_fivestack_modes,
3101 .input_mux = &alc880_capture_source,
3102 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003103 [ALC880_6ST] = {
3104 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003105 .init_verbs = { alc880_volume_init_verbs,
3106 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003107 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3108 .dac_nids = alc880_6st_dac_nids,
3109 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3110 .channel_mode = alc880_sixstack_modes,
3111 .input_mux = &alc880_6stack_capture_source,
3112 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003113 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003114 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003115 .init_verbs = { alc880_volume_init_verbs,
3116 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003117 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3118 .dac_nids = alc880_6st_dac_nids,
3119 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003120 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3121 .channel_mode = alc880_sixstack_modes,
3122 .input_mux = &alc880_6stack_capture_source,
3123 },
3124 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003125 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003126 .init_verbs = { alc880_volume_init_verbs,
3127 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003128 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3130 .dac_nids = alc880_w810_dac_nids,
3131 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003132 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3133 .channel_mode = alc880_w810_modes,
3134 .input_mux = &alc880_capture_source,
3135 },
3136 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003137 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003138 .init_verbs = { alc880_volume_init_verbs,
3139 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003140 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3141 .dac_nids = alc880_z71v_dac_nids,
3142 .dig_out_nid = ALC880_DIGOUT_NID,
3143 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003144 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3145 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003146 .input_mux = &alc880_capture_source,
3147 },
3148 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003149 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003150 .init_verbs = { alc880_volume_init_verbs,
3151 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003152 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3153 .dac_nids = alc880_f1734_dac_nids,
3154 .hp_nid = 0x02,
3155 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3156 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003157 .input_mux = &alc880_f1734_capture_source,
3158 .unsol_event = alc880_uniwill_p53_unsol_event,
3159 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003160 },
3161 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003162 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003163 .init_verbs = { alc880_volume_init_verbs,
3164 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003165 alc880_gpio1_init_verbs },
3166 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3167 .dac_nids = alc880_asus_dac_nids,
3168 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3169 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003170 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003171 .input_mux = &alc880_capture_source,
3172 },
3173 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003174 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003175 .init_verbs = { alc880_volume_init_verbs,
3176 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003177 alc880_gpio1_init_verbs },
3178 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3179 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003180 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003181 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3182 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003183 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003184 .input_mux = &alc880_capture_source,
3185 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003186 [ALC880_ASUS_DIG2] = {
3187 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003188 .init_verbs = { alc880_volume_init_verbs,
3189 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003190 alc880_gpio2_init_verbs }, /* use GPIO2 */
3191 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3192 .dac_nids = alc880_asus_dac_nids,
3193 .dig_out_nid = ALC880_DIGOUT_NID,
3194 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3195 .channel_mode = alc880_asus_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 Iwai16ded522005-06-10 19:58:24 +02003199 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003200 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003201 .init_verbs = { alc880_volume_init_verbs,
3202 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003203 alc880_gpio1_init_verbs },
3204 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3205 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003206 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003207 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3208 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003209 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003210 .input_mux = &alc880_capture_source,
3211 },
3212 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003213 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003214 .init_verbs = { alc880_volume_init_verbs,
3215 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003216 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3217 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003218 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003219 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3220 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003221 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003222 .input_mux = &alc880_capture_source,
3223 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003224 [ALC880_UNIWILL] = {
3225 .mixers = { alc880_uniwill_mixer },
3226 .init_verbs = { alc880_volume_init_verbs,
3227 alc880_uniwill_init_verbs },
3228 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3229 .dac_nids = alc880_asus_dac_nids,
3230 .dig_out_nid = ALC880_DIGOUT_NID,
3231 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3232 .channel_mode = alc880_threestack_modes,
3233 .need_dac_fix = 1,
3234 .input_mux = &alc880_capture_source,
3235 .unsol_event = alc880_uniwill_unsol_event,
3236 .init_hook = alc880_uniwill_automute,
3237 },
3238 [ALC880_UNIWILL_P53] = {
3239 .mixers = { alc880_uniwill_p53_mixer },
3240 .init_verbs = { alc880_volume_init_verbs,
3241 alc880_uniwill_p53_init_verbs },
3242 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3243 .dac_nids = alc880_asus_dac_nids,
3244 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003245 .channel_mode = alc880_threestack_modes,
3246 .input_mux = &alc880_capture_source,
3247 .unsol_event = alc880_uniwill_p53_unsol_event,
3248 .init_hook = alc880_uniwill_p53_hp_automute,
3249 },
3250 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003251 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003252 alc880_pcbeep_mixer, },
3253 .init_verbs = { alc880_volume_init_verbs,
3254 alc880_uniwill_p53_init_verbs,
3255 alc880_beep_init_verbs },
3256 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3257 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003258 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003259 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3260 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003261 .input_mux = &alc880_capture_source,
3262 .unsol_event = alc880_uniwill_p53_unsol_event,
3263 .init_hook = alc880_uniwill_p53_hp_automute,
3264 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003265 [ALC880_CLEVO] = {
3266 .mixers = { alc880_three_stack_mixer },
3267 .init_verbs = { alc880_volume_init_verbs,
3268 alc880_pin_clevo_init_verbs },
3269 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3270 .dac_nids = alc880_dac_nids,
3271 .hp_nid = 0x03,
3272 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3273 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003274 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003275 .input_mux = &alc880_capture_source,
3276 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003277 [ALC880_LG] = {
3278 .mixers = { alc880_lg_mixer },
3279 .init_verbs = { alc880_volume_init_verbs,
3280 alc880_lg_init_verbs },
3281 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3282 .dac_nids = alc880_lg_dac_nids,
3283 .dig_out_nid = ALC880_DIGOUT_NID,
3284 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3285 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003286 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003287 .input_mux = &alc880_lg_capture_source,
3288 .unsol_event = alc880_lg_unsol_event,
3289 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003290#ifdef CONFIG_SND_HDA_POWER_SAVE
3291 .loopbacks = alc880_lg_loopbacks,
3292#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003293 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003294 [ALC880_LG_LW] = {
3295 .mixers = { alc880_lg_lw_mixer },
3296 .init_verbs = { alc880_volume_init_verbs,
3297 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003298 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003299 .dac_nids = alc880_dac_nids,
3300 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003301 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3302 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003303 .input_mux = &alc880_lg_lw_capture_source,
3304 .unsol_event = alc880_lg_lw_unsol_event,
3305 .init_hook = alc880_lg_lw_automute,
3306 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003307 [ALC880_MEDION_RIM] = {
3308 .mixers = { alc880_medion_rim_mixer },
3309 .init_verbs = { alc880_volume_init_verbs,
3310 alc880_medion_rim_init_verbs,
3311 alc_gpio2_init_verbs },
3312 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3313 .dac_nids = alc880_dac_nids,
3314 .dig_out_nid = ALC880_DIGOUT_NID,
3315 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3316 .channel_mode = alc880_2_jack_modes,
3317 .input_mux = &alc880_medion_rim_capture_source,
3318 .unsol_event = alc880_medion_rim_unsol_event,
3319 .init_hook = alc880_medion_rim_automute,
3320 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003321#ifdef CONFIG_SND_DEBUG
3322 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003323 .mixers = { alc880_test_mixer },
3324 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003325 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3326 .dac_nids = alc880_test_dac_nids,
3327 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003328 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3329 .channel_mode = alc880_test_modes,
3330 .input_mux = &alc880_test_capture_source,
3331 },
3332#endif
3333};
3334
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003335/*
3336 * Automatic parse of I/O pins from the BIOS configuration
3337 */
3338
3339#define NUM_CONTROL_ALLOC 32
3340#define NUM_VERB_ALLOC 32
3341
3342enum {
3343 ALC_CTL_WIDGET_VOL,
3344 ALC_CTL_WIDGET_MUTE,
3345 ALC_CTL_BIND_MUTE,
3346};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003347static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003348 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3349 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003350 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003351};
3352
3353/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003354static int add_control(struct alc_spec *spec, int type, const char *name,
3355 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003356{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003357 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003358
3359 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3360 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3361
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003362 /* array + terminator */
3363 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3364 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003365 return -ENOMEM;
3366 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003367 memcpy(knew, spec->kctl_alloc,
3368 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003369 kfree(spec->kctl_alloc);
3370 }
3371 spec->kctl_alloc = knew;
3372 spec->num_kctl_alloc = num;
3373 }
3374
3375 knew = &spec->kctl_alloc[spec->num_kctl_used];
3376 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003377 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003378 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003379 return -ENOMEM;
3380 knew->private_value = val;
3381 spec->num_kctl_used++;
3382 return 0;
3383}
3384
3385#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3386#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3387#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3388#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3389#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3390#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3391#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3392#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3393#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3394#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3395#define ALC880_PIN_CD_NID 0x1c
3396
3397/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003398static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3399 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003400{
3401 hda_nid_t nid;
3402 int assigned[4];
3403 int i, j;
3404
3405 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003406 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003407
3408 /* check the pins hardwired to audio widget */
3409 for (i = 0; i < cfg->line_outs; i++) {
3410 nid = cfg->line_out_pins[i];
3411 if (alc880_is_fixed_pin(nid)) {
3412 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003413 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003414 assigned[idx] = 1;
3415 }
3416 }
3417 /* left pins can be connect to any audio widget */
3418 for (i = 0; i < cfg->line_outs; i++) {
3419 nid = cfg->line_out_pins[i];
3420 if (alc880_is_fixed_pin(nid))
3421 continue;
3422 /* search for an empty channel */
3423 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003424 if (!assigned[j]) {
3425 spec->multiout.dac_nids[i] =
3426 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003427 assigned[j] = 1;
3428 break;
3429 }
3430 }
3431 }
3432 spec->multiout.num_dacs = cfg->line_outs;
3433 return 0;
3434}
3435
3436/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003437static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3438 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003439{
3440 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003441 static const char *chname[4] = {
3442 "Front", "Surround", NULL /*CLFE*/, "Side"
3443 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003444 hda_nid_t nid;
3445 int i, err;
3446
3447 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003448 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003449 continue;
3450 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3451 if (i == 2) {
3452 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003453 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3454 "Center Playback Volume",
3455 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3456 HDA_OUTPUT));
3457 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003458 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003459 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3460 "LFE Playback Volume",
3461 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3462 HDA_OUTPUT));
3463 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003464 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003465 err = add_control(spec, ALC_CTL_BIND_MUTE,
3466 "Center Playback Switch",
3467 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3468 HDA_INPUT));
3469 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003470 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003471 err = add_control(spec, ALC_CTL_BIND_MUTE,
3472 "LFE Playback Switch",
3473 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3474 HDA_INPUT));
3475 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003476 return err;
3477 } else {
3478 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003479 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3480 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3481 HDA_OUTPUT));
3482 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003483 return err;
3484 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003485 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3486 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3487 HDA_INPUT));
3488 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003489 return err;
3490 }
3491 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003492 return 0;
3493}
3494
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003495/* add playback controls for speaker and HP outputs */
3496static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3497 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003498{
3499 hda_nid_t nid;
3500 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003501 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003502
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003503 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003504 return 0;
3505
3506 if (alc880_is_fixed_pin(pin)) {
3507 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003508 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003509 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003510 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003511 else
3512 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003513 /* control HP volume/switch on the output mixer amp */
3514 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003515 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003516 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3517 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3518 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003519 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003520 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003521 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3522 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3523 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003524 return err;
3525 } else if (alc880_is_multi_pin(pin)) {
3526 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003527 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003528 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003529 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3530 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3531 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003532 return err;
3533 }
3534 return 0;
3535}
3536
3537/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003538static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3539 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003540 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003541{
3542 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003543 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003544
3545 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003546 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3547 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3548 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003549 return err;
3550 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003551 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3552 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3553 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003554 return err;
3555 return 0;
3556}
3557
3558/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003559static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3560 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003561{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003562 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003563 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003564
3565 for (i = 0; i < AUTO_PIN_LAST; i++) {
3566 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003567 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003568 err = new_analog_input(spec, cfg->input_pins[i],
3569 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003570 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003571 if (err < 0)
3572 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003573 imux->items[imux->num_items].label =
3574 auto_pin_cfg_labels[i];
3575 imux->items[imux->num_items].index =
3576 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003577 imux->num_items++;
3578 }
3579 }
3580 return 0;
3581}
3582
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003583static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3584 unsigned int pin_type)
3585{
3586 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3587 pin_type);
3588 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003589 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3590 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003591}
3592
Kailang Yangdf694da2005-12-05 19:42:22 +01003593static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3594 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003595 int dac_idx)
3596{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003597 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003598 /* need the manual connection? */
3599 if (alc880_is_multi_pin(nid)) {
3600 struct alc_spec *spec = codec->spec;
3601 int idx = alc880_multi_pin_idx(nid);
3602 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3603 AC_VERB_SET_CONNECT_SEL,
3604 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3605 }
3606}
3607
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003608static int get_pin_type(int line_out_type)
3609{
3610 if (line_out_type == AUTO_PIN_HP_OUT)
3611 return PIN_HP;
3612 else
3613 return PIN_OUT;
3614}
3615
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003616static void alc880_auto_init_multi_out(struct hda_codec *codec)
3617{
3618 struct alc_spec *spec = codec->spec;
3619 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003620
3621 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003622 for (i = 0; i < spec->autocfg.line_outs; i++) {
3623 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003624 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3625 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003626 }
3627}
3628
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003629static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003630{
3631 struct alc_spec *spec = codec->spec;
3632 hda_nid_t pin;
3633
Takashi Iwai82bc9552006-03-21 11:24:42 +01003634 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003635 if (pin) /* connect to front */
3636 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003637 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003638 if (pin) /* connect to front */
3639 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3640}
3641
3642static void alc880_auto_init_analog_input(struct hda_codec *codec)
3643{
3644 struct alc_spec *spec = codec->spec;
3645 int i;
3646
3647 for (i = 0; i < AUTO_PIN_LAST; i++) {
3648 hda_nid_t nid = spec->autocfg.input_pins[i];
3649 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003650 snd_hda_codec_write(codec, nid, 0,
3651 AC_VERB_SET_PIN_WIDGET_CONTROL,
3652 i <= AUTO_PIN_FRONT_MIC ?
3653 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003654 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003655 snd_hda_codec_write(codec, nid, 0,
3656 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003657 AMP_OUT_MUTE);
3658 }
3659 }
3660}
3661
3662/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003663/* return 1 if successful, 0 if the proper config is not found,
3664 * or a negative error code
3665 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003666static int alc880_parse_auto_config(struct hda_codec *codec)
3667{
3668 struct alc_spec *spec = codec->spec;
3669 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003670 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003671
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003672 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3673 alc880_ignore);
3674 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003675 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003676 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003677 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003678
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003679 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3680 if (err < 0)
3681 return err;
3682 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3683 if (err < 0)
3684 return err;
3685 err = alc880_auto_create_extra_out(spec,
3686 spec->autocfg.speaker_pins[0],
3687 "Speaker");
3688 if (err < 0)
3689 return err;
3690 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3691 "Headphone");
3692 if (err < 0)
3693 return err;
3694 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3695 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003696 return err;
3697
3698 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3699
3700 if (spec->autocfg.dig_out_pin)
3701 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3702 if (spec->autocfg.dig_in_pin)
3703 spec->dig_in_nid = ALC880_DIGIN_NID;
3704
3705 if (spec->kctl_alloc)
3706 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3707
3708 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3709
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003710 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003711 spec->input_mux = &spec->private_imux;
3712
3713 return 1;
3714}
3715
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003716/* additional initialization for auto-configuration model */
3717static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003718{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003719 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003720 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003721 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003722 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003723 if (spec->unsol_event)
3724 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003725}
3726
3727/*
3728 * OK, here we have finally the patch for ALC880
3729 */
3730
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731static int patch_alc880(struct hda_codec *codec)
3732{
3733 struct alc_spec *spec;
3734 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003735 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003737 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 if (spec == NULL)
3739 return -ENOMEM;
3740
3741 codec->spec = spec;
3742
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003743 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3744 alc880_models,
3745 alc880_cfg_tbl);
3746 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003747 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3748 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003749 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 }
3751
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003752 if (board_config == ALC880_AUTO) {
3753 /* automatic parse from the BIOS config */
3754 err = alc880_parse_auto_config(codec);
3755 if (err < 0) {
3756 alc_free(codec);
3757 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003758 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003759 printk(KERN_INFO
3760 "hda_codec: Cannot set up configuration "
3761 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003762 board_config = ALC880_3ST;
3763 }
3764 }
3765
Kailang Yangdf694da2005-12-05 19:42:22 +01003766 if (board_config != ALC880_AUTO)
3767 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768
3769 spec->stream_name_analog = "ALC880 Analog";
3770 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3771 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003772 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773
3774 spec->stream_name_digital = "ALC880 Digital";
3775 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3776 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3777
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003778 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003779 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003780 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003781 /* get type */
3782 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003783 if (wcap != AC_WID_AUD_IN) {
3784 spec->adc_nids = alc880_adc_nids_alt;
3785 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003786 spec->mixers[spec->num_mixers] =
3787 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003788 spec->num_mixers++;
3789 } else {
3790 spec->adc_nids = alc880_adc_nids;
3791 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3792 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3793 spec->num_mixers++;
3794 }
3795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796
Takashi Iwai2134ea42008-01-10 16:53:55 +01003797 spec->vmaster_nid = 0x0c;
3798
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003800 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003801 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003802#ifdef CONFIG_SND_HDA_POWER_SAVE
3803 if (!spec->loopback.amplist)
3804 spec->loopback.amplist = alc880_loopbacks;
3805#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
3807 return 0;
3808}
3809
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003810
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811/*
3812 * ALC260 support
3813 */
3814
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003815static hda_nid_t alc260_dac_nids[1] = {
3816 /* front */
3817 0x02,
3818};
3819
3820static hda_nid_t alc260_adc_nids[1] = {
3821 /* ADC0 */
3822 0x04,
3823};
3824
Kailang Yangdf694da2005-12-05 19:42:22 +01003825static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003826 /* ADC1 */
3827 0x05,
3828};
3829
Kailang Yangdf694da2005-12-05 19:42:22 +01003830static hda_nid_t alc260_hp_adc_nids[2] = {
3831 /* ADC1, 0 */
3832 0x05, 0x04
3833};
3834
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003835/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3836 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3837 */
3838static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003839 /* ADC0, ADC1 */
3840 0x04, 0x05
3841};
3842
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003843#define ALC260_DIGOUT_NID 0x03
3844#define ALC260_DIGIN_NID 0x06
3845
3846static struct hda_input_mux alc260_capture_source = {
3847 .num_items = 4,
3848 .items = {
3849 { "Mic", 0x0 },
3850 { "Front Mic", 0x1 },
3851 { "Line", 0x2 },
3852 { "CD", 0x4 },
3853 },
3854};
3855
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003856/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003857 * headphone jack and the internal CD lines since these are the only pins at
3858 * which audio can appear. For flexibility, also allow the option of
3859 * recording the mixer output on the second ADC (ADC0 doesn't have a
3860 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003861 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003862static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3863 {
3864 .num_items = 3,
3865 .items = {
3866 { "Mic/Line", 0x0 },
3867 { "CD", 0x4 },
3868 { "Headphone", 0x2 },
3869 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003870 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003871 {
3872 .num_items = 4,
3873 .items = {
3874 { "Mic/Line", 0x0 },
3875 { "CD", 0x4 },
3876 { "Headphone", 0x2 },
3877 { "Mixer", 0x5 },
3878 },
3879 },
3880
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003881};
3882
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003883/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3884 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003885 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003886static struct hda_input_mux alc260_acer_capture_sources[2] = {
3887 {
3888 .num_items = 4,
3889 .items = {
3890 { "Mic", 0x0 },
3891 { "Line", 0x2 },
3892 { "CD", 0x4 },
3893 { "Headphone", 0x5 },
3894 },
3895 },
3896 {
3897 .num_items = 5,
3898 .items = {
3899 { "Mic", 0x0 },
3900 { "Line", 0x2 },
3901 { "CD", 0x4 },
3902 { "Headphone", 0x6 },
3903 { "Mixer", 0x5 },
3904 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003905 },
3906};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907/*
3908 * This is just place-holder, so there's something for alc_build_pcms to look
3909 * at when it calculates the maximum number of channels. ALC260 has no mixer
3910 * element which allows changing the channel mode, so the verb list is
3911 * never used.
3912 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003913static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 { 2, NULL },
3915};
3916
Kailang Yangdf694da2005-12-05 19:42:22 +01003917
3918/* Mixer combinations
3919 *
3920 * basic: base_output + input + pc_beep + capture
3921 * HP: base_output + input + capture_alt
3922 * HP_3013: hp_3013 + input + capture
3923 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003924 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003925 */
3926
3927static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003928 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003929 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003930 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3931 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3932 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3933 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3934 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003935};
Kailang Yangdf694da2005-12-05 19:42:22 +01003936
3937static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3939 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3940 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3941 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3942 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3943 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3944 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3945 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 { } /* end */
3947};
3948
Kailang Yangdf694da2005-12-05 19:42:22 +01003949static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3950 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3951 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3952 { } /* end */
3953};
3954
Takashi Iwaibec15c32008-01-28 18:16:30 +01003955/* update HP, line and mono out pins according to the master switch */
3956static void alc260_hp_master_update(struct hda_codec *codec,
3957 hda_nid_t hp, hda_nid_t line,
3958 hda_nid_t mono)
3959{
3960 struct alc_spec *spec = codec->spec;
3961 unsigned int val = spec->master_sw ? PIN_HP : 0;
3962 /* change HP and line-out pins */
3963 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3964 val);
3965 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3966 val);
3967 /* mono (speaker) depending on the HP jack sense */
3968 val = (val && !spec->jack_present) ? PIN_OUT : 0;
3969 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3970 val);
3971}
3972
3973static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
3974 struct snd_ctl_elem_value *ucontrol)
3975{
3976 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3977 struct alc_spec *spec = codec->spec;
3978 *ucontrol->value.integer.value = spec->master_sw;
3979 return 0;
3980}
3981
3982static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
3983 struct snd_ctl_elem_value *ucontrol)
3984{
3985 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3986 struct alc_spec *spec = codec->spec;
3987 int val = !!*ucontrol->value.integer.value;
3988 hda_nid_t hp, line, mono;
3989
3990 if (val == spec->master_sw)
3991 return 0;
3992 spec->master_sw = val;
3993 hp = (kcontrol->private_value >> 16) & 0xff;
3994 line = (kcontrol->private_value >> 8) & 0xff;
3995 mono = kcontrol->private_value & 0xff;
3996 alc260_hp_master_update(codec, hp, line, mono);
3997 return 1;
3998}
3999
4000static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4001 {
4002 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4003 .name = "Master Playback Switch",
4004 .info = snd_ctl_boolean_mono_info,
4005 .get = alc260_hp_master_sw_get,
4006 .put = alc260_hp_master_sw_put,
4007 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4008 },
4009 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4010 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4011 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4012 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4013 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4014 HDA_OUTPUT),
4015 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4016 { } /* end */
4017};
4018
4019static struct hda_verb alc260_hp_unsol_verbs[] = {
4020 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4021 {},
4022};
4023
4024static void alc260_hp_automute(struct hda_codec *codec)
4025{
4026 struct alc_spec *spec = codec->spec;
4027 unsigned int present;
4028
4029 present = snd_hda_codec_read(codec, 0x10, 0,
4030 AC_VERB_GET_PIN_SENSE, 0);
4031 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4032 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4033}
4034
4035static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4036{
4037 if ((res >> 26) == ALC880_HP_EVENT)
4038 alc260_hp_automute(codec);
4039}
4040
Kailang Yangdf694da2005-12-05 19:42:22 +01004041static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004042 {
4043 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4044 .name = "Master Playback Switch",
4045 .info = snd_ctl_boolean_mono_info,
4046 .get = alc260_hp_master_sw_get,
4047 .put = alc260_hp_master_sw_put,
4048 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
4049 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004050 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4051 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4052 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4053 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4054 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4055 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004056 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4057 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004058 { } /* end */
4059};
4060
Takashi Iwaibec15c32008-01-28 18:16:30 +01004061static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4062 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4063 {},
4064};
4065
4066static void alc260_hp_3013_automute(struct hda_codec *codec)
4067{
4068 struct alc_spec *spec = codec->spec;
4069 unsigned int present;
4070
4071 present = snd_hda_codec_read(codec, 0x15, 0,
4072 AC_VERB_GET_PIN_SENSE, 0);
4073 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4074 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
4075}
4076
4077static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4078 unsigned int res)
4079{
4080 if ((res >> 26) == ALC880_HP_EVENT)
4081 alc260_hp_3013_automute(codec);
4082}
4083
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004084/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
4085 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4086 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004087static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004088 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004089 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004090 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004091 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4092 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4093 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4094 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004095 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004096 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4097 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004098 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4099 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004100 { } /* end */
4101};
4102
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004103/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4104 * versions of the ALC260 don't act on requests to enable mic bias from NID
4105 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4106 * datasheet doesn't mention this restriction. At this stage it's not clear
4107 * whether this behaviour is intentional or is a hardware bug in chip
4108 * revisions available in early 2006. Therefore for now allow the
4109 * "Headphone Jack Mode" control to span all choices, but if it turns out
4110 * that the lack of mic bias for this NID is intentional we could change the
4111 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4112 *
4113 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4114 * don't appear to make the mic bias available from the "line" jack, even
4115 * though the NID used for this jack (0x14) can supply it. The theory is
4116 * that perhaps Acer have included blocking capacitors between the ALC260
4117 * and the output jack. If this turns out to be the case for all such
4118 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4119 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004120 *
4121 * The C20x Tablet series have a mono internal speaker which is controlled
4122 * via the chip's Mono sum widget and pin complex, so include the necessary
4123 * controls for such models. On models without a "mono speaker" the control
4124 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004125 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004126static struct snd_kcontrol_new alc260_acer_mixer[] = {
4127 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4128 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004129 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004130 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004131 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004132 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004133 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004134 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4135 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4136 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4137 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4138 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4139 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4140 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4141 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4142 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4143 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4144 { } /* end */
4145};
4146
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004147/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4148 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4149 */
4150static struct snd_kcontrol_new alc260_will_mixer[] = {
4151 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4152 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4153 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4154 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4155 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4156 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4157 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4158 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4159 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4160 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4161 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4162 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4163 { } /* end */
4164};
4165
4166/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4167 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4168 */
4169static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4170 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4171 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4173 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4174 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4175 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4176 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4177 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4178 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4179 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4180 { } /* end */
4181};
4182
Kailang Yangdf694da2005-12-05 19:42:22 +01004183/* capture mixer elements */
4184static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004185 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4186 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004187 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4188 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004189 {
4190 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004191 /* The multiple "Capture Source" controls confuse alsamixer
4192 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004193 */
4194 /* .name = "Capture Source", */
4195 .name = "Input Source",
4196 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004197 .info = alc_mux_enum_info,
4198 .get = alc_mux_enum_get,
4199 .put = alc_mux_enum_put,
4200 },
4201 { } /* end */
4202};
4203
Kailang Yangdf694da2005-12-05 19:42:22 +01004204static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4205 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4206 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4207 {
4208 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4209 /* The multiple "Capture Source" controls confuse alsamixer
4210 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004211 */
4212 /* .name = "Capture Source", */
4213 .name = "Input Source",
4214 .count = 1,
4215 .info = alc_mux_enum_info,
4216 .get = alc_mux_enum_get,
4217 .put = alc_mux_enum_put,
4218 },
4219 { } /* end */
4220};
4221
4222/*
4223 * initialization verbs
4224 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225static struct hda_verb alc260_init_verbs[] = {
4226 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004227 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004229 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004231 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004233 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004235 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004237 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004239 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004241 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004243 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4244 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004245 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 /* set connection select to line in (default select for this ADC) */
4247 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004248 /* mute capture amp left and right */
4249 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4250 /* set connection select to line in (default select for this ADC) */
4251 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004252 /* set vol=0 Line-Out mixer amp left and right */
4253 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4254 /* unmute pin widget amp left and right (no gain on this amp) */
4255 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4256 /* set vol=0 HP mixer amp left and right */
4257 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4258 /* unmute pin widget amp left and right (no gain on this amp) */
4259 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4260 /* set vol=0 Mono mixer amp left and right */
4261 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4262 /* unmute pin widget amp left and right (no gain on this amp) */
4263 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4264 /* unmute LINE-2 out pin */
4265 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004266 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4267 * Line In 2 = 0x03
4268 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004269 /* mute analog inputs */
4270 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4271 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004276 /* mute Front out path */
4277 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4278 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4279 /* mute Headphone out path */
4280 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4281 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4282 /* mute Mono out path */
4283 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4284 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 { }
4286};
4287
Takashi Iwai474167d2006-05-17 17:17:43 +02004288#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004289static struct hda_verb alc260_hp_init_verbs[] = {
4290 /* Headphone and output */
4291 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4292 /* mono output */
4293 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4294 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4295 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4296 /* Mic2 (front panel) pin widget for input and vref at 80% */
4297 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4298 /* Line In pin widget for input */
4299 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4300 /* Line-2 pin widget for output */
4301 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4302 /* CD pin widget for input */
4303 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4304 /* unmute amp left and right */
4305 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4306 /* set connection select to line in (default select for this ADC) */
4307 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4308 /* unmute Line-Out mixer amp left and right (volume = 0) */
4309 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4310 /* mute pin widget amp left and right (no gain on this amp) */
4311 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4312 /* unmute HP mixer amp left and right (volume = 0) */
4313 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4314 /* mute pin widget amp left and right (no gain on this amp) */
4315 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004316 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4317 * Line In 2 = 0x03
4318 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004319 /* mute analog inputs */
4320 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4321 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4322 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4323 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4324 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004325 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4326 /* Unmute Front out path */
4327 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4328 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4329 /* Unmute Headphone out path */
4330 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4331 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4332 /* Unmute Mono out path */
4333 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4334 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4335 { }
4336};
Takashi Iwai474167d2006-05-17 17:17:43 +02004337#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004338
4339static struct hda_verb alc260_hp_3013_init_verbs[] = {
4340 /* Line out and output */
4341 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4342 /* mono output */
4343 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4344 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4345 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4346 /* Mic2 (front panel) pin widget for input and vref at 80% */
4347 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4348 /* Line In pin widget for input */
4349 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4350 /* Headphone pin widget for output */
4351 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4352 /* CD pin widget for input */
4353 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4354 /* unmute amp left and right */
4355 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4356 /* set connection select to line in (default select for this ADC) */
4357 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4358 /* unmute Line-Out mixer amp left and right (volume = 0) */
4359 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4360 /* mute pin widget amp left and right (no gain on this amp) */
4361 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4362 /* unmute HP mixer amp left and right (volume = 0) */
4363 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4364 /* mute pin widget amp left and right (no gain on this amp) */
4365 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004366 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4367 * Line In 2 = 0x03
4368 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004369 /* mute analog inputs */
4370 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4371 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4372 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4373 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4374 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004375 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4376 /* Unmute Front out path */
4377 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4378 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4379 /* Unmute Headphone out path */
4380 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4381 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4382 /* Unmute Mono out path */
4383 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4384 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4385 { }
4386};
4387
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004388/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004389 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4390 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004391 */
4392static struct hda_verb alc260_fujitsu_init_verbs[] = {
4393 /* Disable all GPIOs */
4394 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4395 /* Internal speaker is connected to headphone pin */
4396 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4397 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4398 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004399 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4400 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4401 /* Ensure all other unused pins are disabled and muted. */
4402 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4403 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004404 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004405 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004406 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004407 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4408 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4409 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004410
Jonathan Woithef7ace402006-02-28 11:46:14 +01004411 /* Disable digital (SPDIF) pins */
4412 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4413 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004414
Jonathan Woithef7ace402006-02-28 11:46:14 +01004415 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4416 * when acting as an output.
4417 */
4418 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4419
4420 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004421 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4422 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4423 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4424 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4425 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4426 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4427 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4428 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4429 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004430
Jonathan Woithef7ace402006-02-28 11:46:14 +01004431 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4432 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4433 /* Unmute Line1 pin widget output buffer since it starts as an output.
4434 * If the pin mode is changed by the user the pin mode control will
4435 * take care of enabling the pin's input/output buffers as needed.
4436 * Therefore there's no need to enable the input buffer at this
4437 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004438 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004439 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004440 /* Unmute input buffer of pin widget used for Line-in (no equiv
4441 * mixer ctrl)
4442 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004443 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004444
Jonathan Woithef7ace402006-02-28 11:46:14 +01004445 /* Mute capture amp left and right */
4446 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4447 /* Set ADC connection select to match default mixer setting - line
4448 * in (on mic1 pin)
4449 */
4450 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004451
Jonathan Woithef7ace402006-02-28 11:46:14 +01004452 /* Do the same for the second ADC: mute capture input amp and
4453 * set ADC connection to line in (on mic1 pin)
4454 */
4455 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4456 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004457
Jonathan Woithef7ace402006-02-28 11:46:14 +01004458 /* Mute all inputs to mixer widget (even unconnected ones) */
4459 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4460 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4461 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4462 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4463 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4464 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4465 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004467
4468 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004469};
4470
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004471/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4472 * similar laptops (adapted from Fujitsu init verbs).
4473 */
4474static struct hda_verb alc260_acer_init_verbs[] = {
4475 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4476 * the headphone jack. Turn this on and rely on the standard mute
4477 * methods whenever the user wants to turn these outputs off.
4478 */
4479 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4480 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4481 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4482 /* Internal speaker/Headphone jack is connected to Line-out pin */
4483 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4484 /* Internal microphone/Mic jack is connected to Mic1 pin */
4485 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4486 /* Line In jack is connected to Line1 pin */
4487 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004488 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4489 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004490 /* Ensure all other unused pins are disabled and muted. */
4491 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4492 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004493 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4494 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4496 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4497 /* Disable digital (SPDIF) pins */
4498 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4499 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4500
4501 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4502 * bus when acting as outputs.
4503 */
4504 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4505 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4506
4507 /* Start with output sum widgets muted and their output gains at min */
4508 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4509 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4510 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4511 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4512 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4513 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4514 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4515 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4516 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4517
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004518 /* Unmute Line-out pin widget amp left and right
4519 * (no equiv mixer ctrl)
4520 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004521 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004522 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4523 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004524 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4525 * inputs. If the pin mode is changed by the user the pin mode control
4526 * will take care of enabling the pin's input/output buffers as needed.
4527 * Therefore there's no need to enable the input buffer at this
4528 * stage.
4529 */
4530 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4531 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4532
4533 /* Mute capture amp left and right */
4534 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4535 /* Set ADC connection select to match default mixer setting - mic
4536 * (on mic1 pin)
4537 */
4538 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4539
4540 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004541 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004542 */
4543 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004544 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004545
4546 /* Mute all inputs to mixer widget (even unconnected ones) */
4547 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4548 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4549 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4550 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4551 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4552 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4553 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4554 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4555
4556 { }
4557};
4558
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004559static struct hda_verb alc260_will_verbs[] = {
4560 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4561 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4562 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4563 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4564 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4565 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4566 {}
4567};
4568
4569static struct hda_verb alc260_replacer_672v_verbs[] = {
4570 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4571 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4572 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4573
4574 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4575 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4576 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4577
4578 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4579 {}
4580};
4581
4582/* toggle speaker-output according to the hp-jack state */
4583static void alc260_replacer_672v_automute(struct hda_codec *codec)
4584{
4585 unsigned int present;
4586
4587 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4588 present = snd_hda_codec_read(codec, 0x0f, 0,
4589 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4590 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004591 snd_hda_codec_write_cache(codec, 0x01, 0,
4592 AC_VERB_SET_GPIO_DATA, 1);
4593 snd_hda_codec_write_cache(codec, 0x0f, 0,
4594 AC_VERB_SET_PIN_WIDGET_CONTROL,
4595 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004596 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004597 snd_hda_codec_write_cache(codec, 0x01, 0,
4598 AC_VERB_SET_GPIO_DATA, 0);
4599 snd_hda_codec_write_cache(codec, 0x0f, 0,
4600 AC_VERB_SET_PIN_WIDGET_CONTROL,
4601 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004602 }
4603}
4604
4605static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4606 unsigned int res)
4607{
4608 if ((res >> 26) == ALC880_HP_EVENT)
4609 alc260_replacer_672v_automute(codec);
4610}
4611
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004612/* Test configuration for debugging, modelled after the ALC880 test
4613 * configuration.
4614 */
4615#ifdef CONFIG_SND_DEBUG
4616static hda_nid_t alc260_test_dac_nids[1] = {
4617 0x02,
4618};
4619static hda_nid_t alc260_test_adc_nids[2] = {
4620 0x04, 0x05,
4621};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004622/* For testing the ALC260, each input MUX needs its own definition since
4623 * the signal assignments are different. This assumes that the first ADC
4624 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004625 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004626static struct hda_input_mux alc260_test_capture_sources[2] = {
4627 {
4628 .num_items = 7,
4629 .items = {
4630 { "MIC1 pin", 0x0 },
4631 { "MIC2 pin", 0x1 },
4632 { "LINE1 pin", 0x2 },
4633 { "LINE2 pin", 0x3 },
4634 { "CD pin", 0x4 },
4635 { "LINE-OUT pin", 0x5 },
4636 { "HP-OUT pin", 0x6 },
4637 },
4638 },
4639 {
4640 .num_items = 8,
4641 .items = {
4642 { "MIC1 pin", 0x0 },
4643 { "MIC2 pin", 0x1 },
4644 { "LINE1 pin", 0x2 },
4645 { "LINE2 pin", 0x3 },
4646 { "CD pin", 0x4 },
4647 { "Mixer", 0x5 },
4648 { "LINE-OUT pin", 0x6 },
4649 { "HP-OUT pin", 0x7 },
4650 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004651 },
4652};
4653static struct snd_kcontrol_new alc260_test_mixer[] = {
4654 /* Output driver widgets */
4655 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4656 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4657 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4658 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4659 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4660 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4661
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004662 /* Modes for retasking pin widgets
4663 * Note: the ALC260 doesn't seem to act on requests to enable mic
4664 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4665 * mention this restriction. At this stage it's not clear whether
4666 * this behaviour is intentional or is a hardware bug in chip
4667 * revisions available at least up until early 2006. Therefore for
4668 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4669 * choices, but if it turns out that the lack of mic bias for these
4670 * NIDs is intentional we could change their modes from
4671 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4672 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004673 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4674 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4675 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4676 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4677 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4678 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4679
4680 /* Loopback mixer controls */
4681 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4682 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4683 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4684 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4685 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4686 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4687 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4688 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4689 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4690 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4691 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4692 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4693 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4694 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4695 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4696 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004697
4698 /* Controls for GPIO pins, assuming they are configured as outputs */
4699 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4700 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4701 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4702 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4703
Jonathan Woithe92621f12006-02-28 11:47:47 +01004704 /* Switches to allow the digital IO pins to be enabled. The datasheet
4705 * is ambigious as to which NID is which; testing on laptops which
4706 * make this output available should provide clarification.
4707 */
4708 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4709 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4710
Jonathan Woithef8225f62008-01-08 12:16:54 +01004711 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4712 * this output to turn on an external amplifier.
4713 */
4714 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4715 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4716
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004717 { } /* end */
4718};
4719static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004720 /* Enable all GPIOs as outputs with an initial value of 0 */
4721 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4722 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4723 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4724
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004725 /* Enable retasking pins as output, initially without power amp */
4726 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4727 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4728 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4730 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4731 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4732
Jonathan Woithe92621f12006-02-28 11:47:47 +01004733 /* Disable digital (SPDIF) pins initially, but users can enable
4734 * them via a mixer switch. In the case of SPDIF-out, this initverb
4735 * payload also sets the generation to 0, output to be in "consumer"
4736 * PCM format, copyright asserted, no pre-emphasis and no validity
4737 * control.
4738 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004739 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4740 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4741
Jonathan Woithef7ace402006-02-28 11:46:14 +01004742 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004743 * OUT1 sum bus when acting as an output.
4744 */
4745 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4746 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4747 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4748 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4749
4750 /* Start with output sum widgets muted and their output gains at min */
4751 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4752 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4753 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4754 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4755 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4756 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4757 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4758 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4759 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4760
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004761 /* Unmute retasking pin widget output buffers since the default
4762 * state appears to be output. As the pin mode is changed by the
4763 * user the pin mode control will take care of enabling the pin's
4764 * input/output buffers as needed.
4765 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004766 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4767 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4768 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4769 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4770 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4771 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4772 /* Also unmute the mono-out pin widget */
4773 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4774
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004775 /* Mute capture amp left and right */
4776 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004777 /* Set ADC connection select to match default mixer setting (mic1
4778 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004779 */
4780 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4781
4782 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004783 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004784 */
4785 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4786 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4787
4788 /* Mute all inputs to mixer widget (even unconnected ones) */
4789 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4792 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4793 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4794 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4795 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4796 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4797
4798 { }
4799};
4800#endif
4801
Takashi Iwai63300792008-01-24 15:31:36 +01004802#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4803#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004805#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4806#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4807
Kailang Yangdf694da2005-12-05 19:42:22 +01004808/*
4809 * for BIOS auto-configuration
4810 */
4811
4812static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4813 const char *pfx)
4814{
4815 hda_nid_t nid_vol;
4816 unsigned long vol_val, sw_val;
4817 char name[32];
4818 int err;
4819
4820 if (nid >= 0x0f && nid < 0x11) {
4821 nid_vol = nid - 0x7;
4822 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4823 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4824 } else if (nid == 0x11) {
4825 nid_vol = nid - 0x7;
4826 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4827 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4828 } else if (nid >= 0x12 && nid <= 0x15) {
4829 nid_vol = 0x08;
4830 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4831 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4832 } else
4833 return 0; /* N/A */
4834
4835 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004836 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4837 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004838 return err;
4839 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004840 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4841 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004842 return err;
4843 return 1;
4844}
4845
4846/* add playback controls from the parsed DAC table */
4847static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4848 const struct auto_pin_cfg *cfg)
4849{
4850 hda_nid_t nid;
4851 int err;
4852
4853 spec->multiout.num_dacs = 1;
4854 spec->multiout.dac_nids = spec->private_dac_nids;
4855 spec->multiout.dac_nids[0] = 0x02;
4856
4857 nid = cfg->line_out_pins[0];
4858 if (nid) {
4859 err = alc260_add_playback_controls(spec, nid, "Front");
4860 if (err < 0)
4861 return err;
4862 }
4863
Takashi Iwai82bc9552006-03-21 11:24:42 +01004864 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004865 if (nid) {
4866 err = alc260_add_playback_controls(spec, nid, "Speaker");
4867 if (err < 0)
4868 return err;
4869 }
4870
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004871 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004872 if (nid) {
4873 err = alc260_add_playback_controls(spec, nid, "Headphone");
4874 if (err < 0)
4875 return err;
4876 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004877 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004878}
4879
4880/* create playback/capture controls for input pins */
4881static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4882 const struct auto_pin_cfg *cfg)
4883{
Kailang Yangdf694da2005-12-05 19:42:22 +01004884 struct hda_input_mux *imux = &spec->private_imux;
4885 int i, err, idx;
4886
4887 for (i = 0; i < AUTO_PIN_LAST; i++) {
4888 if (cfg->input_pins[i] >= 0x12) {
4889 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004890 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004891 auto_pin_cfg_labels[i], idx,
4892 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004893 if (err < 0)
4894 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004895 imux->items[imux->num_items].label =
4896 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004897 imux->items[imux->num_items].index = idx;
4898 imux->num_items++;
4899 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004900 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004901 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004902 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004903 auto_pin_cfg_labels[i], idx,
4904 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004905 if (err < 0)
4906 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004907 imux->items[imux->num_items].label =
4908 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004909 imux->items[imux->num_items].index = idx;
4910 imux->num_items++;
4911 }
4912 }
4913 return 0;
4914}
4915
4916static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4917 hda_nid_t nid, int pin_type,
4918 int sel_idx)
4919{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004920 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01004921 /* need the manual connection? */
4922 if (nid >= 0x12) {
4923 int idx = nid - 0x12;
4924 snd_hda_codec_write(codec, idx + 0x0b, 0,
4925 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004926 }
4927}
4928
4929static void alc260_auto_init_multi_out(struct hda_codec *codec)
4930{
4931 struct alc_spec *spec = codec->spec;
4932 hda_nid_t nid;
4933
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004934 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004935 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004936 if (nid) {
4937 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4938 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4939 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004940
Takashi Iwai82bc9552006-03-21 11:24:42 +01004941 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004942 if (nid)
4943 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4944
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004945 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004946 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004947 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004948}
Kailang Yangdf694da2005-12-05 19:42:22 +01004949
4950#define ALC260_PIN_CD_NID 0x16
4951static void alc260_auto_init_analog_input(struct hda_codec *codec)
4952{
4953 struct alc_spec *spec = codec->spec;
4954 int i;
4955
4956 for (i = 0; i < AUTO_PIN_LAST; i++) {
4957 hda_nid_t nid = spec->autocfg.input_pins[i];
4958 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004959 snd_hda_codec_write(codec, nid, 0,
4960 AC_VERB_SET_PIN_WIDGET_CONTROL,
4961 i <= AUTO_PIN_FRONT_MIC ?
4962 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004963 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004964 snd_hda_codec_write(codec, nid, 0,
4965 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004966 AMP_OUT_MUTE);
4967 }
4968 }
4969}
4970
4971/*
4972 * generic initialization of ADC, input mixers and output mixers
4973 */
4974static struct hda_verb alc260_volume_init_verbs[] = {
4975 /*
4976 * Unmute ADC0-1 and set the default input to mic-in
4977 */
4978 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4979 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4980 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4981 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4982
4983 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4984 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004985 * Note: PASD motherboards uses the Line In 2 as the input for
4986 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004987 */
4988 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004989 /* mute analog inputs */
4990 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4991 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4992 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4993 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4994 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004995
4996 /*
4997 * Set up output mixers (0x08 - 0x0a)
4998 */
4999 /* set vol=0 to output mixers */
5000 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5001 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5002 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5003 /* set up input amps for analog loopback */
5004 /* Amp Indices: DAC = 0, mixer = 1 */
5005 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5006 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5007 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5008 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5009 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5010 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5011
5012 { }
5013};
5014
5015static int alc260_parse_auto_config(struct hda_codec *codec)
5016{
5017 struct alc_spec *spec = codec->spec;
5018 unsigned int wcap;
5019 int err;
5020 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5021
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005022 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5023 alc260_ignore);
5024 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005025 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005026 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5027 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005028 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005029 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01005030 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005031 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5032 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005033 return err;
5034
5035 spec->multiout.max_channels = 2;
5036
5037 if (spec->autocfg.dig_out_pin)
5038 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
5039 if (spec->kctl_alloc)
5040 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
5041
5042 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
5043
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005044 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01005045 spec->input_mux = &spec->private_imux;
5046
5047 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005048 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01005049 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
Takashi Iwai67ebcb02008-02-19 15:03:57 +01005050 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Kailang Yangdf694da2005-12-05 19:42:22 +01005051 spec->adc_nids = alc260_adc_nids_alt;
5052 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
5053 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01005054 } else {
5055 spec->adc_nids = alc260_adc_nids;
5056 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
5057 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01005058 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01005059 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01005060
5061 return 1;
5062}
5063
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005064/* additional initialization for auto-configuration model */
5065static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005066{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005067 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005068 alc260_auto_init_multi_out(codec);
5069 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005070 if (spec->unsol_event)
5071 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005072}
5073
Takashi Iwaicb53c622007-08-10 17:21:45 +02005074#ifdef CONFIG_SND_HDA_POWER_SAVE
5075static struct hda_amp_list alc260_loopbacks[] = {
5076 { 0x07, HDA_INPUT, 0 },
5077 { 0x07, HDA_INPUT, 1 },
5078 { 0x07, HDA_INPUT, 2 },
5079 { 0x07, HDA_INPUT, 3 },
5080 { 0x07, HDA_INPUT, 4 },
5081 { } /* end */
5082};
5083#endif
5084
Kailang Yangdf694da2005-12-05 19:42:22 +01005085/*
5086 * ALC260 configurations
5087 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005088static const char *alc260_models[ALC260_MODEL_LAST] = {
5089 [ALC260_BASIC] = "basic",
5090 [ALC260_HP] = "hp",
5091 [ALC260_HP_3013] = "hp-3013",
5092 [ALC260_FUJITSU_S702X] = "fujitsu",
5093 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005094 [ALC260_WILL] = "will",
5095 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005096#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005097 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005098#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005099 [ALC260_AUTO] = "auto",
5100};
5101
5102static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005103 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005104 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005105 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005106 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005107 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
5108 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
5109 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
5110 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5111 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5112 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5113 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5114 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5115 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5116 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5117 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5118 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005119 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005120 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005121 {}
5122};
5123
Kailang Yangdf694da2005-12-05 19:42:22 +01005124static struct alc_config_preset alc260_presets[] = {
5125 [ALC260_BASIC] = {
5126 .mixers = { alc260_base_output_mixer,
5127 alc260_input_mixer,
5128 alc260_pc_beep_mixer,
5129 alc260_capture_mixer },
5130 .init_verbs = { alc260_init_verbs },
5131 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5132 .dac_nids = alc260_dac_nids,
5133 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5134 .adc_nids = alc260_adc_nids,
5135 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5136 .channel_mode = alc260_modes,
5137 .input_mux = &alc260_capture_source,
5138 },
5139 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005140 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005141 alc260_input_mixer,
5142 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005143 .init_verbs = { alc260_init_verbs,
5144 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005145 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5146 .dac_nids = alc260_dac_nids,
5147 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5148 .adc_nids = alc260_hp_adc_nids,
5149 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5150 .channel_mode = alc260_modes,
5151 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005152 .unsol_event = alc260_hp_unsol_event,
5153 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005154 },
5155 [ALC260_HP_3013] = {
5156 .mixers = { alc260_hp_3013_mixer,
5157 alc260_input_mixer,
5158 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005159 .init_verbs = { alc260_hp_3013_init_verbs,
5160 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005161 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5162 .dac_nids = alc260_dac_nids,
5163 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5164 .adc_nids = alc260_hp_adc_nids,
5165 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5166 .channel_mode = alc260_modes,
5167 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005168 .unsol_event = alc260_hp_3013_unsol_event,
5169 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005170 },
5171 [ALC260_FUJITSU_S702X] = {
5172 .mixers = { alc260_fujitsu_mixer,
5173 alc260_capture_mixer },
5174 .init_verbs = { alc260_fujitsu_init_verbs },
5175 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5176 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005177 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5178 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005179 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5180 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005181 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5182 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005183 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005184 [ALC260_ACER] = {
5185 .mixers = { alc260_acer_mixer,
5186 alc260_capture_mixer },
5187 .init_verbs = { alc260_acer_init_verbs },
5188 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5189 .dac_nids = alc260_dac_nids,
5190 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5191 .adc_nids = alc260_dual_adc_nids,
5192 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5193 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005194 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5195 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005196 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005197 [ALC260_WILL] = {
5198 .mixers = { alc260_will_mixer,
5199 alc260_capture_mixer },
5200 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5201 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5202 .dac_nids = alc260_dac_nids,
5203 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5204 .adc_nids = alc260_adc_nids,
5205 .dig_out_nid = ALC260_DIGOUT_NID,
5206 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5207 .channel_mode = alc260_modes,
5208 .input_mux = &alc260_capture_source,
5209 },
5210 [ALC260_REPLACER_672V] = {
5211 .mixers = { alc260_replacer_672v_mixer,
5212 alc260_capture_mixer },
5213 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5214 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5215 .dac_nids = alc260_dac_nids,
5216 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5217 .adc_nids = alc260_adc_nids,
5218 .dig_out_nid = ALC260_DIGOUT_NID,
5219 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5220 .channel_mode = alc260_modes,
5221 .input_mux = &alc260_capture_source,
5222 .unsol_event = alc260_replacer_672v_unsol_event,
5223 .init_hook = alc260_replacer_672v_automute,
5224 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005225#ifdef CONFIG_SND_DEBUG
5226 [ALC260_TEST] = {
5227 .mixers = { alc260_test_mixer,
5228 alc260_capture_mixer },
5229 .init_verbs = { alc260_test_init_verbs },
5230 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5231 .dac_nids = alc260_test_dac_nids,
5232 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5233 .adc_nids = alc260_test_adc_nids,
5234 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5235 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005236 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5237 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005238 },
5239#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005240};
5241
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242static int patch_alc260(struct hda_codec *codec)
5243{
5244 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005245 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005247 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 if (spec == NULL)
5249 return -ENOMEM;
5250
5251 codec->spec = spec;
5252
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005253 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5254 alc260_models,
5255 alc260_cfg_tbl);
5256 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005257 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5258 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005259 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005260 }
5261
Kailang Yangdf694da2005-12-05 19:42:22 +01005262 if (board_config == ALC260_AUTO) {
5263 /* automatic parse from the BIOS config */
5264 err = alc260_parse_auto_config(codec);
5265 if (err < 0) {
5266 alc_free(codec);
5267 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005268 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005269 printk(KERN_INFO
5270 "hda_codec: Cannot set up configuration "
5271 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005272 board_config = ALC260_BASIC;
5273 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275
Kailang Yangdf694da2005-12-05 19:42:22 +01005276 if (board_config != ALC260_AUTO)
5277 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278
5279 spec->stream_name_analog = "ALC260 Analog";
5280 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5281 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5282
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005283 spec->stream_name_digital = "ALC260 Digital";
5284 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5285 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5286
Takashi Iwai2134ea42008-01-10 16:53:55 +01005287 spec->vmaster_nid = 0x08;
5288
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005290 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005291 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005292#ifdef CONFIG_SND_HDA_POWER_SAVE
5293 if (!spec->loopback.amplist)
5294 spec->loopback.amplist = alc260_loopbacks;
5295#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296
5297 return 0;
5298}
5299
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005300
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301/*
5302 * ALC882 support
5303 *
5304 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5305 * configuration. Each pin widget can choose any input DACs and a mixer.
5306 * Each ADC is connected from a mixer of all inputs. This makes possible
5307 * 6-channel independent captures.
5308 *
5309 * In addition, an independent DAC for the multi-playback (not used in this
5310 * driver yet).
5311 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005312#define ALC882_DIGOUT_NID 0x06
5313#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005315static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 { 8, NULL }
5317};
5318
5319static hda_nid_t alc882_dac_nids[4] = {
5320 /* front, rear, clfe, rear_surr */
5321 0x02, 0x03, 0x04, 0x05
5322};
5323
Kailang Yangdf694da2005-12-05 19:42:22 +01005324/* identical with ALC880 */
5325#define alc882_adc_nids alc880_adc_nids
5326#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
Takashi Iwaie1406342008-02-11 18:32:32 +01005328static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5329static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5330
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331/* input MUX */
5332/* FIXME: should be a matrix-type input source selection */
5333
5334static struct hda_input_mux alc882_capture_source = {
5335 .num_items = 4,
5336 .items = {
5337 { "Mic", 0x0 },
5338 { "Front Mic", 0x1 },
5339 { "Line", 0x2 },
5340 { "CD", 0x4 },
5341 },
5342};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343#define alc882_mux_enum_info alc_mux_enum_info
5344#define alc882_mux_enum_get alc_mux_enum_get
5345
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005346static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5347 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348{
5349 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5350 struct alc_spec *spec = codec->spec;
5351 const struct hda_input_mux *imux = spec->input_mux;
5352 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai88c71a92008-02-14 17:27:17 +01005353 hda_nid_t nid = spec->capsrc_nids ?
5354 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5356 unsigned int i, idx;
5357
5358 idx = ucontrol->value.enumerated.item[0];
5359 if (idx >= imux->num_items)
5360 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005361 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 return 0;
5363 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005364 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5365 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005366 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005367 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 }
5369 *cur_val = idx;
5370 return 1;
5371}
5372
Kailang Yangdf694da2005-12-05 19:42:22 +01005373/*
Kailang Yang272a5272007-05-14 11:00:38 +02005374 * 2ch mode
5375 */
5376static struct hda_verb alc882_3ST_ch2_init[] = {
5377 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5378 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5379 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5380 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5381 { } /* end */
5382};
5383
5384/*
5385 * 6ch mode
5386 */
5387static struct hda_verb alc882_3ST_ch6_init[] = {
5388 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5389 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5390 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5391 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5392 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5393 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5394 { } /* end */
5395};
5396
5397static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5398 { 2, alc882_3ST_ch2_init },
5399 { 6, alc882_3ST_ch6_init },
5400};
5401
5402/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005403 * 6ch mode
5404 */
5405static struct hda_verb alc882_sixstack_ch6_init[] = {
5406 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5407 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5408 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5409 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5410 { } /* end */
5411};
5412
5413/*
5414 * 8ch mode
5415 */
5416static struct hda_verb alc882_sixstack_ch8_init[] = {
5417 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5418 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5419 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5420 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5421 { } /* end */
5422};
5423
5424static struct hda_channel_mode alc882_sixstack_modes[2] = {
5425 { 6, alc882_sixstack_ch6_init },
5426 { 8, alc882_sixstack_ch8_init },
5427};
5428
Takashi Iwai87350ad2007-08-16 18:19:38 +02005429/*
5430 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5431 */
5432
5433/*
5434 * 2ch mode
5435 */
5436static struct hda_verb alc885_mbp_ch2_init[] = {
5437 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5438 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5439 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5440 { } /* end */
5441};
5442
5443/*
5444 * 6ch mode
5445 */
5446static struct hda_verb alc885_mbp_ch6_init[] = {
5447 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5448 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5449 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5450 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5451 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5452 { } /* end */
5453};
5454
5455static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5456 { 2, alc885_mbp_ch2_init },
5457 { 6, alc885_mbp_ch6_init },
5458};
5459
5460
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5462 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5463 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005464static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005465 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005466 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005467 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005468 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005469 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5470 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005471 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5472 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005473 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005474 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5476 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5477 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5478 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5479 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5480 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005481 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5483 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005484 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5486 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5487 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 { } /* end */
5489};
5490
Takashi Iwai87350ad2007-08-16 18:19:38 +02005491static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005492 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5493 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5494 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5495 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5496 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5497 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005498 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5499 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005500 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005501 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5502 { } /* end */
5503};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005504static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5505 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5506 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5507 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5508 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5509 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5510 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5511 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5512 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5513 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5514 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5515 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5516 { } /* end */
5517};
5518
Kailang Yang272a5272007-05-14 11:00:38 +02005519static struct snd_kcontrol_new alc882_targa_mixer[] = {
5520 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5521 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5522 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5523 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5524 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5525 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5526 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5527 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5528 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005529 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005530 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5531 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005532 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005533 { } /* end */
5534};
5535
5536/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5537 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5538 */
5539static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5540 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5541 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5542 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5543 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5544 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5545 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5546 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5547 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5548 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5549 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5550 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5551 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005552 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005553 { } /* end */
5554};
5555
Takashi Iwai914759b2007-09-06 14:52:04 +02005556static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5557 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5558 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5559 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5560 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5561 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5562 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5563 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5564 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5565 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5566 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5567 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5568 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5569 { } /* end */
5570};
5571
Kailang Yangdf694da2005-12-05 19:42:22 +01005572static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5573 {
5574 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5575 .name = "Channel Mode",
5576 .info = alc_ch_mode_info,
5577 .get = alc_ch_mode_get,
5578 .put = alc_ch_mode_put,
5579 },
5580 { } /* end */
5581};
5582
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583static struct hda_verb alc882_init_verbs[] = {
5584 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005585 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5586 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5587 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005589 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5590 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5591 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005593 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5594 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5595 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005597 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5598 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5599 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005601 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005602 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005603 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005605 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005606 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005607 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005609 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005610 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005611 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005613 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005614 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005615 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005617 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005618 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005619 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5620 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005621 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005622 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5623 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005624 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005625 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5626 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5627 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5628 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5629 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005631 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
5633 /* FIXME: use matrix-type input source selection */
5634 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5635 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005636 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5637 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5638 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5639 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005641 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5642 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5643 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5644 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005646 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5647 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5648 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5649 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5650 /* ADC1: mute amp left and right */
5651 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005652 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005653 /* ADC2: mute amp left and right */
5654 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005655 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005656 /* ADC3: mute amp left and right */
5657 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005658 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659
5660 { }
5661};
5662
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005663static struct hda_verb alc882_eapd_verbs[] = {
5664 /* change to EAPD mode */
5665 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005666 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005667 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005668};
5669
Tobin Davis9102cd12006-12-15 10:02:12 +01005670/* Mac Pro test */
5671static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5672 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5673 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5675 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5676 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5677 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5678 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5679 { } /* end */
5680};
5681
5682static struct hda_verb alc882_macpro_init_verbs[] = {
5683 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5685 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5686 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5687 /* Front Pin: output 0 (0x0c) */
5688 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5689 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5690 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5691 /* Front Mic pin: input vref at 80% */
5692 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5693 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5694 /* Speaker: output */
5695 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5696 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5697 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5698 /* Headphone output (output 0 - 0x0c) */
5699 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5700 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5701 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5702
5703 /* FIXME: use matrix-type input source selection */
5704 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5705 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5706 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5707 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5708 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5709 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5710 /* Input mixer2 */
5711 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5712 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5713 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5714 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5715 /* Input mixer3 */
5716 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5717 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5718 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5719 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5720 /* ADC1: mute amp left and right */
5721 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5722 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5723 /* ADC2: mute amp left and right */
5724 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5725 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5726 /* ADC3: mute amp left and right */
5727 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5728 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5729
5730 { }
5731};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005732
Takashi Iwai87350ad2007-08-16 18:19:38 +02005733/* Macbook Pro rev3 */
5734static struct hda_verb alc885_mbp3_init_verbs[] = {
5735 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5736 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5737 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5738 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5739 /* Rear mixer */
5740 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5741 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5742 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5743 /* Front Pin: output 0 (0x0c) */
5744 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5745 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5746 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5747 /* HP Pin: output 0 (0x0d) */
5748 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5749 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5750 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5751 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5752 /* Mic (rear) pin: input vref at 80% */
5753 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5754 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5755 /* Front Mic pin: input vref at 80% */
5756 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5757 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5758 /* Line In pin: use output 1 when in LineOut mode */
5759 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5760 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5761 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5762
5763 /* FIXME: use matrix-type input source selection */
5764 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5765 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5766 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5767 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5768 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5769 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5770 /* Input mixer2 */
5771 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5772 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5773 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5774 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5775 /* Input mixer3 */
5776 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5777 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5778 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5779 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5780 /* ADC1: mute amp left and right */
5781 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5782 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5783 /* ADC2: mute amp left and right */
5784 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5785 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5786 /* ADC3: mute amp left and right */
5787 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5788 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5789
5790 { }
5791};
5792
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005793/* iMac 24 mixer. */
5794static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5795 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5796 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5797 { } /* end */
5798};
5799
5800/* iMac 24 init verbs. */
5801static struct hda_verb alc885_imac24_init_verbs[] = {
5802 /* Internal speakers: output 0 (0x0c) */
5803 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5804 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5805 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5806 /* Internal speakers: output 0 (0x0c) */
5807 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5808 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5809 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5810 /* Headphone: output 0 (0x0c) */
5811 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5812 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5813 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5814 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5815 /* Front Mic: input vref at 80% */
5816 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5817 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5818 { }
5819};
5820
5821/* Toggle speaker-output according to the hp-jack state */
5822static void alc885_imac24_automute(struct hda_codec *codec)
5823{
5824 unsigned int present;
5825
5826 present = snd_hda_codec_read(codec, 0x14, 0,
5827 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005828 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5829 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5830 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5831 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005832}
5833
5834/* Processes unsolicited events. */
5835static void alc885_imac24_unsol_event(struct hda_codec *codec,
5836 unsigned int res)
5837{
5838 /* Headphone insertion or removal. */
5839 if ((res >> 26) == ALC880_HP_EVENT)
5840 alc885_imac24_automute(codec);
5841}
5842
Takashi Iwai87350ad2007-08-16 18:19:38 +02005843static void alc885_mbp3_automute(struct hda_codec *codec)
5844{
5845 unsigned int present;
5846
5847 present = snd_hda_codec_read(codec, 0x15, 0,
5848 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5849 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5850 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5851 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5852 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5853
5854}
5855static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5856 unsigned int res)
5857{
5858 /* Headphone insertion or removal. */
5859 if ((res >> 26) == ALC880_HP_EVENT)
5860 alc885_mbp3_automute(codec);
5861}
5862
5863
Kailang Yang272a5272007-05-14 11:00:38 +02005864static struct hda_verb alc882_targa_verbs[] = {
5865 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5866 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5867
5868 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5869 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5870
5871 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5872 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5873 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5874
5875 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5876 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5877 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5878 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5879 { } /* end */
5880};
5881
5882/* toggle speaker-output according to the hp-jack state */
5883static void alc882_targa_automute(struct hda_codec *codec)
5884{
5885 unsigned int present;
5886
5887 present = snd_hda_codec_read(codec, 0x14, 0,
5888 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005889 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5890 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005891 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5892 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005893}
5894
5895static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5896{
5897 /* Looks like the unsol event is incompatible with the standard
5898 * definition. 4bit tag is placed at 26 bit!
5899 */
5900 if (((res >> 26) == ALC880_HP_EVENT)) {
5901 alc882_targa_automute(codec);
5902 }
5903}
5904
5905static struct hda_verb alc882_asus_a7j_verbs[] = {
5906 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5907 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5908
5909 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5910 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5911 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5912
5913 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5914 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5915 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5916
5917 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5918 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5919 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5920 { } /* end */
5921};
5922
Takashi Iwai914759b2007-09-06 14:52:04 +02005923static struct hda_verb alc882_asus_a7m_verbs[] = {
5924 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5925 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5926
5927 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5928 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5929 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5930
5931 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5932 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5933 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5934
5935 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5936 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5937 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5938 { } /* end */
5939};
5940
Tobin Davis9102cd12006-12-15 10:02:12 +01005941static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5942{
5943 unsigned int gpiostate, gpiomask, gpiodir;
5944
5945 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5946 AC_VERB_GET_GPIO_DATA, 0);
5947
5948 if (!muted)
5949 gpiostate |= (1 << pin);
5950 else
5951 gpiostate &= ~(1 << pin);
5952
5953 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5954 AC_VERB_GET_GPIO_MASK, 0);
5955 gpiomask |= (1 << pin);
5956
5957 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5958 AC_VERB_GET_GPIO_DIRECTION, 0);
5959 gpiodir |= (1 << pin);
5960
5961
5962 snd_hda_codec_write(codec, codec->afg, 0,
5963 AC_VERB_SET_GPIO_MASK, gpiomask);
5964 snd_hda_codec_write(codec, codec->afg, 0,
5965 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5966
5967 msleep(1);
5968
5969 snd_hda_codec_write(codec, codec->afg, 0,
5970 AC_VERB_SET_GPIO_DATA, gpiostate);
5971}
5972
Takashi Iwai7debbe52007-08-16 15:01:03 +02005973/* set up GPIO at initialization */
5974static void alc885_macpro_init_hook(struct hda_codec *codec)
5975{
5976 alc882_gpio_mute(codec, 0, 0);
5977 alc882_gpio_mute(codec, 1, 0);
5978}
5979
5980/* set up GPIO and update auto-muting at initialization */
5981static void alc885_imac24_init_hook(struct hda_codec *codec)
5982{
5983 alc885_macpro_init_hook(codec);
5984 alc885_imac24_automute(codec);
5985}
5986
Kailang Yangdf694da2005-12-05 19:42:22 +01005987/*
5988 * generic initialization of ADC, input mixers and output mixers
5989 */
5990static struct hda_verb alc882_auto_init_verbs[] = {
5991 /*
5992 * Unmute ADC0-2 and set the default input to mic-in
5993 */
5994 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5995 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5996 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5997 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5998 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5999 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6000
Takashi Iwaicb53c622007-08-10 17:21:45 +02006001 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006002 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006003 * Note: PASD motherboards uses the Line In 2 as the input for
6004 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006005 */
6006 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006007 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006012
6013 /*
6014 * Set up output mixers (0x0c - 0x0f)
6015 */
6016 /* set vol=0 to output mixers */
6017 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6018 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6019 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6020 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6021 /* set up input amps for analog loopback */
6022 /* Amp Indices: DAC = 0, mixer = 1 */
6023 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6024 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6025 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6026 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6027 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6028 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6029 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6030 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6031 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6032 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6033
6034 /* FIXME: use matrix-type input source selection */
6035 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6036 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6037 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6038 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6039 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6040 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6041 /* Input mixer2 */
6042 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6043 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6044 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6045 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6046 /* Input mixer3 */
6047 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6048 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6049 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6050 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6051
6052 { }
6053};
6054
6055/* capture mixer elements */
6056static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
6057 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6058 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6059 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6060 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6061 {
6062 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6063 /* The multiple "Capture Source" controls confuse alsamixer
6064 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006065 */
6066 /* .name = "Capture Source", */
6067 .name = "Input Source",
6068 .count = 2,
6069 .info = alc882_mux_enum_info,
6070 .get = alc882_mux_enum_get,
6071 .put = alc882_mux_enum_put,
6072 },
6073 { } /* end */
6074};
6075
6076static struct snd_kcontrol_new alc882_capture_mixer[] = {
6077 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
6078 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
6079 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
6080 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
6081 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
6082 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
6083 {
6084 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6085 /* The multiple "Capture Source" controls confuse alsamixer
6086 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006087 */
6088 /* .name = "Capture Source", */
6089 .name = "Input Source",
6090 .count = 3,
6091 .info = alc882_mux_enum_info,
6092 .get = alc882_mux_enum_get,
6093 .put = alc882_mux_enum_put,
6094 },
6095 { } /* end */
6096};
6097
Takashi Iwaicb53c622007-08-10 17:21:45 +02006098#ifdef CONFIG_SND_HDA_POWER_SAVE
6099#define alc882_loopbacks alc880_loopbacks
6100#endif
6101
Kailang Yangdf694da2005-12-05 19:42:22 +01006102/* pcm configuration: identiacal with ALC880 */
6103#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6104#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6105#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6106#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6107
6108/*
6109 * configuration and preset
6110 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006111static const char *alc882_models[ALC882_MODEL_LAST] = {
6112 [ALC882_3ST_DIG] = "3stack-dig",
6113 [ALC882_6ST_DIG] = "6stack-dig",
6114 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006115 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006116 [ALC882_TARGA] = "targa",
6117 [ALC882_ASUS_A7J] = "asus-a7j",
6118 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006119 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006120 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006121 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006122 [ALC882_AUTO] = "auto",
6123};
6124
6125static struct snd_pci_quirk alc882_cfg_tbl[] = {
6126 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006127 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006128 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006129 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006130 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006131 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006132 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006133 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006134 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006135 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6136 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6137 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006138 {}
6139};
6140
6141static struct alc_config_preset alc882_presets[] = {
6142 [ALC882_3ST_DIG] = {
6143 .mixers = { alc882_base_mixer },
6144 .init_verbs = { alc882_init_verbs },
6145 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6146 .dac_nids = alc882_dac_nids,
6147 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006148 .dig_in_nid = ALC882_DIGIN_NID,
6149 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6150 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006151 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006152 .input_mux = &alc882_capture_source,
6153 },
6154 [ALC882_6ST_DIG] = {
6155 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6156 .init_verbs = { alc882_init_verbs },
6157 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6158 .dac_nids = alc882_dac_nids,
6159 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006160 .dig_in_nid = ALC882_DIGIN_NID,
6161 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6162 .channel_mode = alc882_sixstack_modes,
6163 .input_mux = &alc882_capture_source,
6164 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006165 [ALC882_ARIMA] = {
6166 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6167 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6168 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6169 .dac_nids = alc882_dac_nids,
6170 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6171 .channel_mode = alc882_sixstack_modes,
6172 .input_mux = &alc882_capture_source,
6173 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006174 [ALC882_W2JC] = {
6175 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6176 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6177 alc880_gpio1_init_verbs },
6178 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6179 .dac_nids = alc882_dac_nids,
6180 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6181 .channel_mode = alc880_threestack_modes,
6182 .need_dac_fix = 1,
6183 .input_mux = &alc882_capture_source,
6184 .dig_out_nid = ALC882_DIGOUT_NID,
6185 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006186 [ALC885_MBP3] = {
6187 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6188 .init_verbs = { alc885_mbp3_init_verbs,
6189 alc880_gpio1_init_verbs },
6190 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6191 .dac_nids = alc882_dac_nids,
6192 .channel_mode = alc885_mbp_6ch_modes,
6193 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6194 .input_mux = &alc882_capture_source,
6195 .dig_out_nid = ALC882_DIGOUT_NID,
6196 .dig_in_nid = ALC882_DIGIN_NID,
6197 .unsol_event = alc885_mbp3_unsol_event,
6198 .init_hook = alc885_mbp3_automute,
6199 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006200 [ALC885_MACPRO] = {
6201 .mixers = { alc882_macpro_mixer },
6202 .init_verbs = { alc882_macpro_init_verbs },
6203 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6204 .dac_nids = alc882_dac_nids,
6205 .dig_out_nid = ALC882_DIGOUT_NID,
6206 .dig_in_nid = ALC882_DIGIN_NID,
6207 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6208 .channel_mode = alc882_ch_modes,
6209 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006210 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006211 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006212 [ALC885_IMAC24] = {
6213 .mixers = { alc885_imac24_mixer },
6214 .init_verbs = { alc885_imac24_init_verbs },
6215 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6216 .dac_nids = alc882_dac_nids,
6217 .dig_out_nid = ALC882_DIGOUT_NID,
6218 .dig_in_nid = ALC882_DIGIN_NID,
6219 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6220 .channel_mode = alc882_ch_modes,
6221 .input_mux = &alc882_capture_source,
6222 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006223 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006224 },
Kailang Yang272a5272007-05-14 11:00:38 +02006225 [ALC882_TARGA] = {
6226 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6227 alc882_capture_mixer },
6228 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6229 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6230 .dac_nids = alc882_dac_nids,
6231 .dig_out_nid = ALC882_DIGOUT_NID,
6232 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6233 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006234 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006235 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6236 .channel_mode = alc882_3ST_6ch_modes,
6237 .need_dac_fix = 1,
6238 .input_mux = &alc882_capture_source,
6239 .unsol_event = alc882_targa_unsol_event,
6240 .init_hook = alc882_targa_automute,
6241 },
6242 [ALC882_ASUS_A7J] = {
6243 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6244 alc882_capture_mixer },
6245 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6246 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6247 .dac_nids = alc882_dac_nids,
6248 .dig_out_nid = ALC882_DIGOUT_NID,
6249 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6250 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006251 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006252 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6253 .channel_mode = alc882_3ST_6ch_modes,
6254 .need_dac_fix = 1,
6255 .input_mux = &alc882_capture_source,
6256 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006257 [ALC882_ASUS_A7M] = {
6258 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6259 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6260 alc880_gpio1_init_verbs,
6261 alc882_asus_a7m_verbs },
6262 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6263 .dac_nids = alc882_dac_nids,
6264 .dig_out_nid = ALC882_DIGOUT_NID,
6265 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6266 .channel_mode = alc880_threestack_modes,
6267 .need_dac_fix = 1,
6268 .input_mux = &alc882_capture_source,
6269 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006270};
6271
6272
6273/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006274 * Pin config fixes
6275 */
6276enum {
6277 PINFIX_ABIT_AW9D_MAX
6278};
6279
6280static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6281 { 0x15, 0x01080104 }, /* side */
6282 { 0x16, 0x01011012 }, /* rear */
6283 { 0x17, 0x01016011 }, /* clfe */
6284 { }
6285};
6286
6287static const struct alc_pincfg *alc882_pin_fixes[] = {
6288 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6289};
6290
6291static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6292 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6293 {}
6294};
6295
6296/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006297 * BIOS auto configuration
6298 */
6299static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6300 hda_nid_t nid, int pin_type,
6301 int dac_idx)
6302{
6303 /* set as output */
6304 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006305 int idx;
6306
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006307 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006308 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6309 idx = 4;
6310 else
6311 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006312 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6313
6314}
6315
6316static void alc882_auto_init_multi_out(struct hda_codec *codec)
6317{
6318 struct alc_spec *spec = codec->spec;
6319 int i;
6320
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006321 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006322 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006323 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006324 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006325 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006326 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006327 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006328 }
6329}
6330
6331static void alc882_auto_init_hp_out(struct hda_codec *codec)
6332{
6333 struct alc_spec *spec = codec->spec;
6334 hda_nid_t pin;
6335
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006336 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006337 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006338 /* use dac 0 */
6339 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006340 pin = spec->autocfg.speaker_pins[0];
6341 if (pin)
6342 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006343}
6344
6345#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6346#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6347
6348static void alc882_auto_init_analog_input(struct hda_codec *codec)
6349{
6350 struct alc_spec *spec = codec->spec;
6351 int i;
6352
6353 for (i = 0; i < AUTO_PIN_LAST; i++) {
6354 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006355 unsigned int vref;
6356 if (!nid)
6357 continue;
6358 vref = PIN_IN;
6359 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
6360 if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) &
6361 AC_PINCAP_VREF_80)
6362 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006363 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006364 snd_hda_codec_write(codec, nid, 0,
6365 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6366 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6367 snd_hda_codec_write(codec, nid, 0,
6368 AC_VERB_SET_AMP_GAIN_MUTE,
6369 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006370 }
6371}
6372
Takashi Iwai776e1842007-08-29 15:07:11 +02006373/* add mic boosts if needed */
6374static int alc_auto_add_mic_boost(struct hda_codec *codec)
6375{
6376 struct alc_spec *spec = codec->spec;
6377 int err;
6378 hda_nid_t nid;
6379
6380 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006381 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006382 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6383 "Mic Boost",
6384 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6385 if (err < 0)
6386 return err;
6387 }
6388 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006389 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006390 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6391 "Front Mic Boost",
6392 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6393 if (err < 0)
6394 return err;
6395 }
6396 return 0;
6397}
6398
Kailang Yangdf694da2005-12-05 19:42:22 +01006399/* almost identical with ALC880 parser... */
6400static int alc882_parse_auto_config(struct hda_codec *codec)
6401{
6402 struct alc_spec *spec = codec->spec;
6403 int err = alc880_parse_auto_config(codec);
6404
6405 if (err < 0)
6406 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006407 else if (!err)
6408 return 0; /* no config found */
6409
6410 err = alc_auto_add_mic_boost(codec);
6411 if (err < 0)
6412 return err;
6413
6414 /* hack - override the init verbs */
6415 spec->init_verbs[0] = alc882_auto_init_verbs;
6416
6417 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006418}
6419
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006420/* additional initialization for auto-configuration model */
6421static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006422{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006423 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006424 alc882_auto_init_multi_out(codec);
6425 alc882_auto_init_hp_out(codec);
6426 alc882_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006427 if (spec->unsol_event)
6428 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006429}
6430
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006431static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6432
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433static int patch_alc882(struct hda_codec *codec)
6434{
6435 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006436 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006438 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439 if (spec == NULL)
6440 return -ENOMEM;
6441
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 codec->spec = spec;
6443
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006444 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6445 alc882_models,
6446 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Kailang Yangdf694da2005-12-05 19:42:22 +01006448 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006449 /* Pick up systems that don't supply PCI SSID */
6450 switch (codec->subsystem_id) {
6451 case 0x106b0c00: /* Mac Pro */
6452 board_config = ALC885_MACPRO;
6453 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006454 case 0x106b1000: /* iMac 24 */
6455 board_config = ALC885_IMAC24;
6456 break;
Jiang zhe3d5fa2e2008-01-10 13:05:47 +01006457 case 0x106b00a1: /* Macbook */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006458 case 0x106b2c00: /* Macbook Pro rev3 */
6459 board_config = ALC885_MBP3;
6460 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006461 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006462 /* ALC889A is handled better as ALC888-compatible */
6463 if (codec->revision_id == 0x100103) {
6464 alc_free(codec);
6465 return patch_alc883(codec);
6466 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006467 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6468 "trying auto-probe from BIOS...\n");
6469 board_config = ALC882_AUTO;
6470 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006471 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006472
Takashi Iwaif95474e2007-07-10 00:47:43 +02006473 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6474
Kailang Yangdf694da2005-12-05 19:42:22 +01006475 if (board_config == ALC882_AUTO) {
6476 /* automatic parse from the BIOS config */
6477 err = alc882_parse_auto_config(codec);
6478 if (err < 0) {
6479 alc_free(codec);
6480 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006481 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006482 printk(KERN_INFO
6483 "hda_codec: Cannot set up configuration "
6484 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006485 board_config = ALC882_3ST_DIG;
6486 }
6487 }
6488
6489 if (board_config != ALC882_AUTO)
6490 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
6492 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006493 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6494 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006495 /* FIXME: setup DAC5 */
6496 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6497 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498
6499 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006500 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6501 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006503 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006504 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006505 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006506 /* get type */
6507 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006508 if (wcap != AC_WID_AUD_IN) {
6509 spec->adc_nids = alc882_adc_nids_alt;
6510 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006511 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006512 spec->mixers[spec->num_mixers] =
6513 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006514 spec->num_mixers++;
6515 } else {
6516 spec->adc_nids = alc882_adc_nids;
6517 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006518 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006519 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6520 spec->num_mixers++;
6521 }
6522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523
Takashi Iwai2134ea42008-01-10 16:53:55 +01006524 spec->vmaster_nid = 0x0c;
6525
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006527 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006528 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006529#ifdef CONFIG_SND_HDA_POWER_SAVE
6530 if (!spec->loopback.amplist)
6531 spec->loopback.amplist = alc882_loopbacks;
6532#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533
6534 return 0;
6535}
6536
6537/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006538 * ALC883 support
6539 *
6540 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6541 * configuration. Each pin widget can choose any input DACs and a mixer.
6542 * Each ADC is connected from a mixer of all inputs. This makes possible
6543 * 6-channel independent captures.
6544 *
6545 * In addition, an independent DAC for the multi-playback (not used in this
6546 * driver yet).
6547 */
6548#define ALC883_DIGOUT_NID 0x06
6549#define ALC883_DIGIN_NID 0x0a
6550
6551static hda_nid_t alc883_dac_nids[4] = {
6552 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006553 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006554};
6555
6556static hda_nid_t alc883_adc_nids[2] = {
6557 /* ADC1-2 */
6558 0x08, 0x09,
6559};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006560
Takashi Iwaie1406342008-02-11 18:32:32 +01006561static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6562
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006563/* input MUX */
6564/* FIXME: should be a matrix-type input source selection */
6565
6566static struct hda_input_mux alc883_capture_source = {
6567 .num_items = 4,
6568 .items = {
6569 { "Mic", 0x0 },
6570 { "Front Mic", 0x1 },
6571 { "Line", 0x2 },
6572 { "CD", 0x4 },
6573 },
6574};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006575
6576static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6577 .num_items = 2,
6578 .items = {
6579 { "Mic", 0x1 },
6580 { "Line", 0x2 },
6581 },
6582};
6583
Kailang Yang272a5272007-05-14 11:00:38 +02006584static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6585 .num_items = 4,
6586 .items = {
6587 { "Mic", 0x0 },
6588 { "iMic", 0x1 },
6589 { "Line", 0x2 },
6590 { "CD", 0x4 },
6591 },
6592};
6593
Jiang zhefb97dc62008-03-06 11:07:11 +01006594static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6595 .num_items = 2,
6596 .items = {
6597 { "Mic", 0x0 },
6598 { "Int Mic", 0x1 },
6599 },
6600};
6601
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006602#define alc883_mux_enum_info alc_mux_enum_info
6603#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006604/* ALC883 has the ALC882-type input selection */
6605#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006606
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006607/*
6608 * 2ch mode
6609 */
6610static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6611 { 2, NULL }
6612};
6613
6614/*
6615 * 2ch mode
6616 */
6617static struct hda_verb alc883_3ST_ch2_init[] = {
6618 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6619 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6620 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6621 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6622 { } /* end */
6623};
6624
6625/*
Tobin Davisb2011312007-09-17 12:45:11 +02006626 * 4ch mode
6627 */
6628static struct hda_verb alc883_3ST_ch4_init[] = {
6629 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6630 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6631 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6632 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6633 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6634 { } /* end */
6635};
6636
6637/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006638 * 6ch mode
6639 */
6640static struct hda_verb alc883_3ST_ch6_init[] = {
6641 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6642 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6643 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6644 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6645 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6646 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6647 { } /* end */
6648};
6649
Tobin Davisb2011312007-09-17 12:45:11 +02006650static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006651 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006652 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006653 { 6, alc883_3ST_ch6_init },
6654};
6655
6656/*
6657 * 6ch mode
6658 */
6659static struct hda_verb alc883_sixstack_ch6_init[] = {
6660 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6661 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6662 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6663 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6664 { } /* end */
6665};
6666
6667/*
6668 * 8ch mode
6669 */
6670static struct hda_verb alc883_sixstack_ch8_init[] = {
6671 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6672 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6673 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6674 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6675 { } /* end */
6676};
6677
6678static struct hda_channel_mode alc883_sixstack_modes[2] = {
6679 { 6, alc883_sixstack_ch6_init },
6680 { 8, alc883_sixstack_ch8_init },
6681};
6682
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006683static struct hda_verb alc883_medion_eapd_verbs[] = {
6684 /* eanable EAPD on medion laptop */
6685 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6686 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6687 { }
6688};
6689
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006690/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6691 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6692 */
6693
6694static struct snd_kcontrol_new alc883_base_mixer[] = {
6695 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6696 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6697 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6698 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6699 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6700 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6701 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6702 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6703 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6704 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6705 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6706 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6707 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6708 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6709 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6710 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006711 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006712 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6713 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006714 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006715 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6716 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6717 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6718 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6719 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6720 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6721 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6722 {
6723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6724 /* .name = "Capture Source", */
6725 .name = "Input Source",
6726 .count = 2,
6727 .info = alc883_mux_enum_info,
6728 .get = alc883_mux_enum_get,
6729 .put = alc883_mux_enum_put,
6730 },
6731 { } /* end */
6732};
6733
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006734static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6735 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6736 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6737 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6738 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6739 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6740 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6741 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6742 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6743 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6744 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6745 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6746 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6747 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6748 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6749 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6750 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6751 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6752 {
6753 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6754 /* .name = "Capture Source", */
6755 .name = "Input Source",
6756 .count = 2,
6757 .info = alc883_mux_enum_info,
6758 .get = alc883_mux_enum_get,
6759 .put = alc883_mux_enum_put,
6760 },
6761 { } /* end */
6762};
6763
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01006764static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01006765 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6766 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
6767 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6768 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
6769 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6770 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6771 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6772 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6773 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6774 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6775 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6776 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6777 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6778 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6779 {
6780 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6781 /* .name = "Capture Source", */
6782 .name = "Input Source",
6783 .count = 2,
6784 .info = alc883_mux_enum_info,
6785 .get = alc883_mux_enum_get,
6786 .put = alc883_mux_enum_put,
6787 },
6788 { } /* end */
6789};
6790
Jiang zhefb97dc62008-03-06 11:07:11 +01006791static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
6792 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6793 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
6794 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6795 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
6796 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6797 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6798 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6799 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6800 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6801 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6802 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6803 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6804 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6805 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6806 {
6807 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6808 /* .name = "Capture Source", */
6809 .name = "Input Source",
6810 .count = 2,
6811 .info = alc883_mux_enum_info,
6812 .get = alc883_mux_enum_get,
6813 .put = alc883_mux_enum_put,
6814 },
6815 { } /* end */
6816};
6817
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006818static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6819 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6820 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6822 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6823 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6824 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6825 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6826 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006827 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006828 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6829 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006830 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006831 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6832 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6833 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6834 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6835 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6836 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6837 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6838 {
6839 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6840 /* .name = "Capture Source", */
6841 .name = "Input Source",
6842 .count = 2,
6843 .info = alc883_mux_enum_info,
6844 .get = alc883_mux_enum_get,
6845 .put = alc883_mux_enum_put,
6846 },
6847 { } /* end */
6848};
6849
6850static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6851 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6852 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6853 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6854 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6855 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6856 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6857 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6858 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6859 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6860 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6861 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6862 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6863 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6864 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006865 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006866 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6867 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006868 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006869 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6870 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6871 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6872 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6873 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6874 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6875 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6876 {
6877 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6878 /* .name = "Capture Source", */
6879 .name = "Input Source",
6880 .count = 2,
6881 .info = alc883_mux_enum_info,
6882 .get = alc883_mux_enum_get,
6883 .put = alc883_mux_enum_put,
6884 },
6885 { } /* end */
6886};
6887
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006888static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006889 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6890 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6891 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6892 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6893 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6894 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6895 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6896 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6897 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6898 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6899 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6900 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6901 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6902 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006903 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006904 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6905 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006906 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006907 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6908 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6909 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6910 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6911 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6912
6913 {
6914 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6915 /* .name = "Capture Source", */
6916 .name = "Input Source",
6917 .count = 1,
6918 .info = alc883_mux_enum_info,
6919 .get = alc883_mux_enum_get,
6920 .put = alc883_mux_enum_put,
6921 },
6922 { } /* end */
6923};
6924
Kailang Yangccc656c2006-10-17 12:32:26 +02006925static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6926 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6927 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6928 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6929 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6930 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6931 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6932 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6933 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6934 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6935 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6936 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6937 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6938 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6939 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006940 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006941 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6942 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6943 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6944 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6945 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6946 {
6947 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6948 /* .name = "Capture Source", */
6949 .name = "Input Source",
6950 .count = 2,
6951 .info = alc883_mux_enum_info,
6952 .get = alc883_mux_enum_get,
6953 .put = alc883_mux_enum_put,
6954 },
6955 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006956};
Kailang Yangccc656c2006-10-17 12:32:26 +02006957
6958static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6959 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6961 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6962 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6963 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6964 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006965 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006966 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02006967 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6968 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
6969 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006970 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6971 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6972 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6973 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6974 {
6975 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6976 /* .name = "Capture Source", */
6977 .name = "Input Source",
6978 .count = 2,
6979 .info = alc883_mux_enum_info,
6980 .get = alc883_mux_enum_get,
6981 .put = alc883_mux_enum_put,
6982 },
6983 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006984};
Kailang Yangccc656c2006-10-17 12:32:26 +02006985
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006986static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6987 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6988 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006989 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6990 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006991 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6992 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6993 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6994 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6995 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6996 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6997 {
6998 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6999 /* .name = "Capture Source", */
7000 .name = "Input Source",
7001 .count = 1,
7002 .info = alc883_mux_enum_info,
7003 .get = alc883_mux_enum_get,
7004 .put = alc883_mux_enum_put,
7005 },
7006 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007007};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007008
Kailang Yang272a5272007-05-14 11:00:38 +02007009static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7010 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7011 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7012 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7013 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7014 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7015 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7016 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7017 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7018 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7019 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7020 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7021 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7022 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7023 {
7024 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7025 /* .name = "Capture Source", */
7026 .name = "Input Source",
7027 .count = 2,
7028 .info = alc883_mux_enum_info,
7029 .get = alc883_mux_enum_get,
7030 .put = alc883_mux_enum_put,
7031 },
7032 { } /* end */
7033};
7034
7035static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7036 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7037 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7038 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7039 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7040 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7041 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7042 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7043 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7044 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7045 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7046 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7047 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7048 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7049 {
7050 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7051 /* .name = "Capture Source", */
7052 .name = "Input Source",
7053 .count = 2,
7054 .info = alc883_mux_enum_info,
7055 .get = alc883_mux_enum_get,
7056 .put = alc883_mux_enum_put,
7057 },
7058 { } /* end */
7059};
7060
Tobin Davis2880a862007-08-07 11:50:26 +02007061static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007062 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7063 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007064 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007065 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7066 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007067 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7068 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7069 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007070 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7071 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7072 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7073 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7074 {
7075 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7076 /* .name = "Capture Source", */
7077 .name = "Input Source",
7078 .count = 2,
7079 .info = alc883_mux_enum_info,
7080 .get = alc883_mux_enum_get,
7081 .put = alc883_mux_enum_put,
7082 },
7083 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007084};
Tobin Davis2880a862007-08-07 11:50:26 +02007085
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007086static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7087 {
7088 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7089 .name = "Channel Mode",
7090 .info = alc_ch_mode_info,
7091 .get = alc_ch_mode_get,
7092 .put = alc_ch_mode_put,
7093 },
7094 { } /* end */
7095};
7096
7097static struct hda_verb alc883_init_verbs[] = {
7098 /* ADC1: mute amp left and right */
7099 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7100 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7101 /* ADC2: mute amp left and right */
7102 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7103 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7104 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7105 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7106 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7107 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7108 /* Rear mixer */
7109 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7110 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7111 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7112 /* CLFE mixer */
7113 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7114 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7115 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7116 /* Side mixer */
7117 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7118 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7119 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7120
Takashi Iwaicb53c622007-08-10 17:21:45 +02007121 /* mute analog input loopbacks */
7122 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7123 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7124 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7125 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7126 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007127
7128 /* Front Pin: output 0 (0x0c) */
7129 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7130 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7131 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7132 /* Rear Pin: output 1 (0x0d) */
7133 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7134 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7135 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7136 /* CLFE Pin: output 2 (0x0e) */
7137 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7138 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7139 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7140 /* Side Pin: output 3 (0x0f) */
7141 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7142 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7143 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7144 /* Mic (rear) pin: input vref at 80% */
7145 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7146 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7147 /* Front Mic pin: input vref at 80% */
7148 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7149 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7150 /* Line In pin: input */
7151 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7152 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7153 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7154 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7155 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7156 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7157 /* CD pin widget for input */
7158 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7159
7160 /* FIXME: use matrix-type input source selection */
7161 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7162 /* Input mixer2 */
7163 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7164 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7165 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7166 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7167 /* Input mixer3 */
7168 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7169 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7170 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7171 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7172 { }
7173};
7174
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007175/* toggle speaker-output according to the hp-jack state */
7176static void alc883_mitac_hp_automute(struct hda_codec *codec)
7177{
7178 unsigned int present;
7179
7180 present = snd_hda_codec_read(codec, 0x15, 0,
7181 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7182 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7183 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7184 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7185 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7186}
7187
7188/* auto-toggle front mic */
7189/*
7190static void alc883_mitac_mic_automute(struct hda_codec *codec)
7191{
7192 unsigned int present;
7193 unsigned char bits;
7194
7195 present = snd_hda_codec_read(codec, 0x18, 0,
7196 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7197 bits = present ? HDA_AMP_MUTE : 0;
7198 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7199}
7200*/
7201
7202static void alc883_mitac_automute(struct hda_codec *codec)
7203{
7204 alc883_mitac_hp_automute(codec);
7205 /* alc883_mitac_mic_automute(codec); */
7206}
7207
7208static void alc883_mitac_unsol_event(struct hda_codec *codec,
7209 unsigned int res)
7210{
7211 switch (res >> 26) {
7212 case ALC880_HP_EVENT:
7213 alc883_mitac_hp_automute(codec);
7214 break;
7215 case ALC880_MIC_EVENT:
7216 /* alc883_mitac_mic_automute(codec); */
7217 break;
7218 }
7219}
7220
7221static struct hda_verb alc883_mitac_verbs[] = {
7222 /* HP */
7223 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7225 /* Subwoofer */
7226 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7227 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7228
7229 /* enable unsolicited event */
7230 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7231 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7232
7233 { } /* end */
7234};
7235
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007236static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007237 /* HP */
7238 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7239 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7240 /* Int speaker */
7241 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7242 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7243
7244 /* enable unsolicited event */
7245 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007246 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007247
7248 { } /* end */
7249};
7250
Jiang zhefb97dc62008-03-06 11:07:11 +01007251static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7252 /* HP */
7253 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7254 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7255 /* Subwoofer */
7256 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7257 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7258
7259 /* enable unsolicited event */
7260 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7261
7262 { } /* end */
7263};
7264
Kailang Yangccc656c2006-10-17 12:32:26 +02007265static struct hda_verb alc883_tagra_verbs[] = {
7266 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7267 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7268
7269 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7270 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7271
7272 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7273 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7274 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7275
7276 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007277 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7278 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7279 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007280
7281 { } /* end */
7282};
7283
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007284static struct hda_verb alc883_lenovo_101e_verbs[] = {
7285 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7286 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7287 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7288 { } /* end */
7289};
7290
Kailang Yang272a5272007-05-14 11:00:38 +02007291static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7292 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7293 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7294 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7295 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7296 { } /* end */
7297};
7298
7299static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7300 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7301 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7302 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7303 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7304 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7305 { } /* end */
7306};
7307
Kailang Yang189609a2007-08-20 11:31:23 +02007308static struct hda_verb alc883_haier_w66_verbs[] = {
7309 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7310 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7311
7312 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7313
7314 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7315 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7316 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7317 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7318 { } /* end */
7319};
7320
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007321static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007322 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007323 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7324 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007325 { }
7326};
7327
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007328static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007329 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7330 { }
7331};
7332
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007333static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007334 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7335 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7336 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7337 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7338 { }
7339};
7340
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007341static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007342 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7343 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7344 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7345 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7346 { }
7347};
7348
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007349static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7350 { 2, alc888_3st_hp_2ch_init },
7351 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007352};
7353
Kailang Yang272a5272007-05-14 11:00:38 +02007354/* toggle front-jack and RCA according to the hp-jack state */
7355static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7356{
7357 unsigned int present;
7358
7359 present = snd_hda_codec_read(codec, 0x1b, 0,
7360 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007361 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7362 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7363 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7364 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007365}
7366
7367/* toggle RCA according to the front-jack state */
7368static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7369{
7370 unsigned int present;
7371
7372 present = snd_hda_codec_read(codec, 0x14, 0,
7373 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007374 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7375 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007376}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007377
Kailang Yang272a5272007-05-14 11:00:38 +02007378static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7379 unsigned int res)
7380{
7381 if ((res >> 26) == ALC880_HP_EVENT)
7382 alc888_lenovo_ms7195_front_automute(codec);
7383 if ((res >> 26) == ALC880_FRONT_EVENT)
7384 alc888_lenovo_ms7195_rca_automute(codec);
7385}
7386
7387static struct hda_verb alc883_medion_md2_verbs[] = {
7388 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7389 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7390
7391 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7392
7393 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7394 { } /* end */
7395};
7396
7397/* toggle speaker-output according to the hp-jack state */
7398static void alc883_medion_md2_automute(struct hda_codec *codec)
7399{
7400 unsigned int present;
7401
7402 present = snd_hda_codec_read(codec, 0x14, 0,
7403 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007404 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7405 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007406}
7407
7408static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7409 unsigned int res)
7410{
7411 if ((res >> 26) == ALC880_HP_EVENT)
7412 alc883_medion_md2_automute(codec);
7413}
7414
Kailang Yangccc656c2006-10-17 12:32:26 +02007415/* toggle speaker-output according to the hp-jack state */
7416static void alc883_tagra_automute(struct hda_codec *codec)
7417{
7418 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007419 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007420
7421 present = snd_hda_codec_read(codec, 0x14, 0,
7422 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007423 bits = present ? HDA_AMP_MUTE : 0;
7424 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7425 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007426 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7427 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007428}
7429
7430static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7431{
7432 if ((res >> 26) == ALC880_HP_EVENT)
7433 alc883_tagra_automute(codec);
7434}
7435
Jiang zhe368c7a92008-03-04 11:20:33 +01007436/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007437static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007438{
7439 unsigned int present;
7440 unsigned char bits;
7441
7442 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7443 & AC_PINSENSE_PRESENCE;
7444 bits = present ? HDA_AMP_MUTE : 0;
7445 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7446 HDA_AMP_MUTE, bits);
7447}
7448
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007449static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7450{
7451 unsigned int present;
7452
7453 present = snd_hda_codec_read(codec, 0x18, 0,
7454 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7455 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7456 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7457}
7458
7459static void alc883_clevo_m720_automute(struct hda_codec *codec)
7460{
7461 alc883_clevo_m720_hp_automute(codec);
7462 alc883_clevo_m720_mic_automute(codec);
7463}
7464
7465static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007466 unsigned int res)
7467{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007468 switch (res >> 26) {
7469 case ALC880_HP_EVENT:
7470 alc883_clevo_m720_hp_automute(codec);
7471 break;
7472 case ALC880_MIC_EVENT:
7473 alc883_clevo_m720_mic_automute(codec);
7474 break;
7475 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007476}
7477
Jiang zhefb97dc62008-03-06 11:07:11 +01007478/* toggle speaker-output according to the hp-jack state */
7479static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7480{
7481 unsigned int present;
7482 unsigned char bits;
7483
7484 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7485 & AC_PINSENSE_PRESENCE;
7486 bits = present ? HDA_AMP_MUTE : 0;
7487 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7488 HDA_AMP_MUTE, bits);
7489}
7490
7491static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7492 unsigned int res)
7493{
7494 if ((res >> 26) == ALC880_HP_EVENT)
7495 alc883_2ch_fujitsu_pi2515_automute(codec);
7496}
7497
Kailang Yang189609a2007-08-20 11:31:23 +02007498static void alc883_haier_w66_automute(struct hda_codec *codec)
7499{
7500 unsigned int present;
7501 unsigned char bits;
7502
7503 present = snd_hda_codec_read(codec, 0x1b, 0,
7504 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7505 bits = present ? 0x80 : 0;
7506 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7507 0x80, bits);
7508}
7509
7510static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7511 unsigned int res)
7512{
7513 if ((res >> 26) == ALC880_HP_EVENT)
7514 alc883_haier_w66_automute(codec);
7515}
7516
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007517static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7518{
7519 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007520 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007521
7522 present = snd_hda_codec_read(codec, 0x14, 0,
7523 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007524 bits = present ? HDA_AMP_MUTE : 0;
7525 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7526 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007527}
7528
7529static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7530{
7531 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007532 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007533
7534 present = snd_hda_codec_read(codec, 0x1b, 0,
7535 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007536 bits = present ? HDA_AMP_MUTE : 0;
7537 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7538 HDA_AMP_MUTE, bits);
7539 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7540 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007541}
7542
7543static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7544 unsigned int res)
7545{
7546 if ((res >> 26) == ALC880_HP_EVENT)
7547 alc883_lenovo_101e_all_automute(codec);
7548 if ((res >> 26) == ALC880_FRONT_EVENT)
7549 alc883_lenovo_101e_ispeaker_automute(codec);
7550}
7551
Takashi Iwai676a9b52007-08-16 15:23:35 +02007552/* toggle speaker-output according to the hp-jack state */
7553static void alc883_acer_aspire_automute(struct hda_codec *codec)
7554{
7555 unsigned int present;
7556
7557 present = snd_hda_codec_read(codec, 0x14, 0,
7558 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7559 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7560 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7561 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7562 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7563}
7564
7565static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7566 unsigned int res)
7567{
7568 if ((res >> 26) == ALC880_HP_EVENT)
7569 alc883_acer_aspire_automute(codec);
7570}
7571
Kailang Yangd1a991a2007-08-15 16:21:59 +02007572static struct hda_verb alc883_acer_eapd_verbs[] = {
7573 /* HP Pin: output 0 (0x0c) */
7574 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7575 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7576 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7577 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007578 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7579 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007580 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007581 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7582 /* eanable EAPD on medion laptop */
7583 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7584 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007585 /* enable unsolicited event */
7586 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007587 { }
7588};
7589
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007590static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7591{
7592 unsigned int present;
7593
7594 present = snd_hda_codec_read(codec, 0x1b, 0,
7595 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7596 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7597 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7598 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7599 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7600 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7601 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7602 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7603 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7604}
7605
7606static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7607 unsigned int res)
7608{
7609 switch (res >> 26) {
7610 case ALC880_HP_EVENT:
7611 printk("hp_event\n");
7612 alc888_6st_dell_front_automute(codec);
7613 break;
7614 }
7615}
7616
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007617/*
7618 * generic initialization of ADC, input mixers and output mixers
7619 */
7620static struct hda_verb alc883_auto_init_verbs[] = {
7621 /*
7622 * Unmute ADC0-2 and set the default input to mic-in
7623 */
7624 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7625 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7626 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7627 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7628
Takashi Iwaicb53c622007-08-10 17:21:45 +02007629 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007630 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007631 * Note: PASD motherboards uses the Line In 2 as the input for
7632 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007633 */
7634 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007635 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7636 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7637 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7638 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7639 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007640
7641 /*
7642 * Set up output mixers (0x0c - 0x0f)
7643 */
7644 /* set vol=0 to output mixers */
7645 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7646 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7647 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7648 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7649 /* set up input amps for analog loopback */
7650 /* Amp Indices: DAC = 0, mixer = 1 */
7651 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7652 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7653 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7654 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7655 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7656 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7657 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7658 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7659 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7660 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7661
7662 /* FIXME: use matrix-type input source selection */
7663 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7664 /* Input mixer1 */
7665 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7666 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7667 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007668 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007669 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7670 /* Input mixer2 */
7671 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7672 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7673 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007674 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007675 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007676
7677 { }
7678};
7679
7680/* capture mixer elements */
7681static struct snd_kcontrol_new alc883_capture_mixer[] = {
7682 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7683 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7684 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7685 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7686 {
7687 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7688 /* The multiple "Capture Source" controls confuse alsamixer
7689 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007690 */
7691 /* .name = "Capture Source", */
7692 .name = "Input Source",
7693 .count = 2,
7694 .info = alc882_mux_enum_info,
7695 .get = alc882_mux_enum_get,
7696 .put = alc882_mux_enum_put,
7697 },
7698 { } /* end */
7699};
7700
Takashi Iwaicb53c622007-08-10 17:21:45 +02007701#ifdef CONFIG_SND_HDA_POWER_SAVE
7702#define alc883_loopbacks alc880_loopbacks
7703#endif
7704
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007705/* pcm configuration: identiacal with ALC880 */
7706#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7707#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01007708#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007709#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7710#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7711
7712/*
7713 * configuration and preset
7714 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007715static const char *alc883_models[ALC883_MODEL_LAST] = {
7716 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7717 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7718 [ALC883_3ST_6ch] = "3stack-6ch",
7719 [ALC883_6ST_DIG] = "6stack-dig",
7720 [ALC883_TARGA_DIG] = "targa-dig",
7721 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007722 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007723 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007724 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007725 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007726 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007727 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007728 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7729 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007730 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007731 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007732 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007733 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007734 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01007735 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007736 [ALC883_AUTO] = "auto",
7737};
7738
7739static struct snd_pci_quirk alc883_cfg_tbl[] = {
7740 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007741 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7742 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7743 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7744 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007745 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02007746 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007747 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7748 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01007749 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007750 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Travis Place97ec7102008-05-23 18:31:46 +02007751 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007752 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007753 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7754 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7755 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007756 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007757 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7758 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7759 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02007760 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007761 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01007762 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007763 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7764 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7765 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7766 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7767 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7768 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7769 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7770 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7771 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007772 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7773 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007774 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01007775 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007776 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007777 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007778 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007779 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007780 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
7781 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007782 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007783 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007784 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01007785 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02007786 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007787 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007788 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7789 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007790 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01007791 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02007792 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007793 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007794 {}
7795};
7796
7797static struct alc_config_preset alc883_presets[] = {
7798 [ALC883_3ST_2ch_DIG] = {
7799 .mixers = { alc883_3ST_2ch_mixer },
7800 .init_verbs = { alc883_init_verbs },
7801 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7802 .dac_nids = alc883_dac_nids,
7803 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007804 .dig_in_nid = ALC883_DIGIN_NID,
7805 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7806 .channel_mode = alc883_3ST_2ch_modes,
7807 .input_mux = &alc883_capture_source,
7808 },
7809 [ALC883_3ST_6ch_DIG] = {
7810 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7811 .init_verbs = { alc883_init_verbs },
7812 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7813 .dac_nids = alc883_dac_nids,
7814 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007815 .dig_in_nid = ALC883_DIGIN_NID,
7816 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7817 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007818 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007819 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007820 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007821 [ALC883_3ST_6ch] = {
7822 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7823 .init_verbs = { alc883_init_verbs },
7824 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7825 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007826 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7827 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007828 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007829 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007830 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007831 [ALC883_6ST_DIG] = {
7832 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7833 .init_verbs = { alc883_init_verbs },
7834 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7835 .dac_nids = alc883_dac_nids,
7836 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007837 .dig_in_nid = ALC883_DIGIN_NID,
7838 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7839 .channel_mode = alc883_sixstack_modes,
7840 .input_mux = &alc883_capture_source,
7841 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007842 [ALC883_TARGA_DIG] = {
7843 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7844 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7845 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7846 .dac_nids = alc883_dac_nids,
7847 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007848 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7849 .channel_mode = alc883_3ST_6ch_modes,
7850 .need_dac_fix = 1,
7851 .input_mux = &alc883_capture_source,
7852 .unsol_event = alc883_tagra_unsol_event,
7853 .init_hook = alc883_tagra_automute,
7854 },
7855 [ALC883_TARGA_2ch_DIG] = {
7856 .mixers = { alc883_tagra_2ch_mixer},
7857 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7858 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7859 .dac_nids = alc883_dac_nids,
7860 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007861 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7862 .channel_mode = alc883_3ST_2ch_modes,
7863 .input_mux = &alc883_capture_source,
7864 .unsol_event = alc883_tagra_unsol_event,
7865 .init_hook = alc883_tagra_automute,
7866 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007867 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007868 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007869 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7870 * and the headphone jack. Turn this on and rely on the
7871 * standard mute methods whenever the user wants to turn
7872 * these outputs off.
7873 */
7874 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7875 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7876 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007877 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7878 .channel_mode = alc883_3ST_2ch_modes,
7879 .input_mux = &alc883_capture_source,
7880 },
Tobin Davis2880a862007-08-07 11:50:26 +02007881 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007882 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007883 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007884 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7885 .dac_nids = alc883_dac_nids,
7886 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02007887 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7888 .channel_mode = alc883_3ST_2ch_modes,
7889 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007890 .unsol_event = alc883_acer_aspire_unsol_event,
7891 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007892 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007893 [ALC883_MEDION] = {
7894 .mixers = { alc883_fivestack_mixer,
7895 alc883_chmode_mixer },
7896 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007897 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007898 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7899 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02007900 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7901 .channel_mode = alc883_sixstack_modes,
7902 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007903 },
Kailang Yang272a5272007-05-14 11:00:38 +02007904 [ALC883_MEDION_MD2] = {
7905 .mixers = { alc883_medion_md2_mixer},
7906 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7907 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7908 .dac_nids = alc883_dac_nids,
7909 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007910 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7911 .channel_mode = alc883_3ST_2ch_modes,
7912 .input_mux = &alc883_capture_source,
7913 .unsol_event = alc883_medion_md2_unsol_event,
7914 .init_hook = alc883_medion_md2_automute,
7915 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007916 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007917 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007918 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7919 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7920 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007921 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7922 .channel_mode = alc883_3ST_2ch_modes,
7923 .input_mux = &alc883_capture_source,
7924 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007925 [ALC883_CLEVO_M720] = {
7926 .mixers = { alc883_clevo_m720_mixer },
7927 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01007928 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7929 .dac_nids = alc883_dac_nids,
7930 .dig_out_nid = ALC883_DIGOUT_NID,
7931 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7932 .channel_mode = alc883_3ST_2ch_modes,
7933 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007934 .unsol_event = alc883_clevo_m720_unsol_event,
7935 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01007936 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007937 [ALC883_LENOVO_101E_2ch] = {
7938 .mixers = { alc883_lenovo_101e_2ch_mixer},
7939 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7940 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7941 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007942 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7943 .channel_mode = alc883_3ST_2ch_modes,
7944 .input_mux = &alc883_lenovo_101e_capture_source,
7945 .unsol_event = alc883_lenovo_101e_unsol_event,
7946 .init_hook = alc883_lenovo_101e_all_automute,
7947 },
Kailang Yang272a5272007-05-14 11:00:38 +02007948 [ALC883_LENOVO_NB0763] = {
7949 .mixers = { alc883_lenovo_nb0763_mixer },
7950 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7951 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7952 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007953 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7954 .channel_mode = alc883_3ST_2ch_modes,
7955 .need_dac_fix = 1,
7956 .input_mux = &alc883_lenovo_nb0763_capture_source,
7957 .unsol_event = alc883_medion_md2_unsol_event,
7958 .init_hook = alc883_medion_md2_automute,
7959 },
7960 [ALC888_LENOVO_MS7195_DIG] = {
7961 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7962 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7963 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7964 .dac_nids = alc883_dac_nids,
7965 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007966 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7967 .channel_mode = alc883_3ST_6ch_modes,
7968 .need_dac_fix = 1,
7969 .input_mux = &alc883_capture_source,
7970 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7971 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007972 },
7973 [ALC883_HAIER_W66] = {
7974 .mixers = { alc883_tagra_2ch_mixer},
7975 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7976 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7977 .dac_nids = alc883_dac_nids,
7978 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02007979 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7980 .channel_mode = alc883_3ST_2ch_modes,
7981 .input_mux = &alc883_capture_source,
7982 .unsol_event = alc883_haier_w66_unsol_event,
7983 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01007984 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007985 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01007986 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007987 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007988 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7989 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007990 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7991 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007992 .need_dac_fix = 1,
7993 .input_mux = &alc883_capture_source,
7994 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007995 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01007996 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007997 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
7998 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7999 .dac_nids = alc883_dac_nids,
8000 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008001 .dig_in_nid = ALC883_DIGIN_NID,
8002 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8003 .channel_mode = alc883_sixstack_modes,
8004 .input_mux = &alc883_capture_source,
8005 .unsol_event = alc888_6st_dell_unsol_event,
8006 .init_hook = alc888_6st_dell_front_automute,
8007 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008008 [ALC883_MITAC] = {
8009 .mixers = { alc883_mitac_mixer },
8010 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8011 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8012 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008013 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8014 .channel_mode = alc883_3ST_2ch_modes,
8015 .input_mux = &alc883_capture_source,
8016 .unsol_event = alc883_mitac_unsol_event,
8017 .init_hook = alc883_mitac_automute,
8018 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008019 [ALC883_FUJITSU_PI2515] = {
8020 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8021 .init_verbs = { alc883_init_verbs,
8022 alc883_2ch_fujitsu_pi2515_verbs},
8023 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8024 .dac_nids = alc883_dac_nids,
8025 .dig_out_nid = ALC883_DIGOUT_NID,
8026 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8027 .channel_mode = alc883_3ST_2ch_modes,
8028 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8029 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8030 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8031 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008032};
8033
8034
8035/*
8036 * BIOS auto configuration
8037 */
8038static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8039 hda_nid_t nid, int pin_type,
8040 int dac_idx)
8041{
8042 /* set as output */
8043 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008044 int idx;
8045
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008046 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008047 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8048 idx = 4;
8049 else
8050 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008051 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8052
8053}
8054
8055static void alc883_auto_init_multi_out(struct hda_codec *codec)
8056{
8057 struct alc_spec *spec = codec->spec;
8058 int i;
8059
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008060 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008061 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008062 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008063 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008064 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008065 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008066 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008067 }
8068}
8069
8070static void alc883_auto_init_hp_out(struct hda_codec *codec)
8071{
8072 struct alc_spec *spec = codec->spec;
8073 hda_nid_t pin;
8074
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008075 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008076 if (pin) /* connect to front */
8077 /* use dac 0 */
8078 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008079 pin = spec->autocfg.speaker_pins[0];
8080 if (pin)
8081 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008082}
8083
8084#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8085#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8086
8087static void alc883_auto_init_analog_input(struct hda_codec *codec)
8088{
8089 struct alc_spec *spec = codec->spec;
8090 int i;
8091
8092 for (i = 0; i < AUTO_PIN_LAST; i++) {
8093 hda_nid_t nid = spec->autocfg.input_pins[i];
8094 if (alc883_is_input_pin(nid)) {
8095 snd_hda_codec_write(codec, nid, 0,
8096 AC_VERB_SET_PIN_WIDGET_CONTROL,
8097 (i <= AUTO_PIN_FRONT_MIC ?
8098 PIN_VREF80 : PIN_IN));
8099 if (nid != ALC883_PIN_CD_NID)
8100 snd_hda_codec_write(codec, nid, 0,
8101 AC_VERB_SET_AMP_GAIN_MUTE,
8102 AMP_OUT_MUTE);
8103 }
8104 }
8105}
8106
8107/* almost identical with ALC880 parser... */
8108static int alc883_parse_auto_config(struct hda_codec *codec)
8109{
8110 struct alc_spec *spec = codec->spec;
8111 int err = alc880_parse_auto_config(codec);
8112
8113 if (err < 0)
8114 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008115 else if (!err)
8116 return 0; /* no config found */
8117
8118 err = alc_auto_add_mic_boost(codec);
8119 if (err < 0)
8120 return err;
8121
8122 /* hack - override the init verbs */
8123 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008124 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
8125 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02008126
8127 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008128}
8129
8130/* additional initialization for auto-configuration model */
8131static void alc883_auto_init(struct hda_codec *codec)
8132{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008133 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008134 alc883_auto_init_multi_out(codec);
8135 alc883_auto_init_hp_out(codec);
8136 alc883_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008137 if (spec->unsol_event)
8138 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008139}
8140
8141static int patch_alc883(struct hda_codec *codec)
8142{
8143 struct alc_spec *spec;
8144 int err, board_config;
8145
8146 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8147 if (spec == NULL)
8148 return -ENOMEM;
8149
8150 codec->spec = spec;
8151
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008152 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8153 alc883_models,
8154 alc883_cfg_tbl);
8155 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008156 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8157 "trying auto-probe from BIOS...\n");
8158 board_config = ALC883_AUTO;
8159 }
8160
8161 if (board_config == ALC883_AUTO) {
8162 /* automatic parse from the BIOS config */
8163 err = alc883_parse_auto_config(codec);
8164 if (err < 0) {
8165 alc_free(codec);
8166 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008167 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008168 printk(KERN_INFO
8169 "hda_codec: Cannot set up configuration "
8170 "from BIOS. Using base mode...\n");
8171 board_config = ALC883_3ST_2ch_DIG;
8172 }
8173 }
8174
8175 if (board_config != ALC883_AUTO)
8176 setup_preset(spec, &alc883_presets[board_config]);
8177
8178 spec->stream_name_analog = "ALC883 Analog";
8179 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8180 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008181 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008182
8183 spec->stream_name_digital = "ALC883 Digital";
8184 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8185 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8186
Takashi Iwaie1406342008-02-11 18:32:32 +01008187 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8188 spec->adc_nids = alc883_adc_nids;
8189 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008190
Takashi Iwai2134ea42008-01-10 16:53:55 +01008191 spec->vmaster_nid = 0x0c;
8192
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008193 codec->patch_ops = alc_patch_ops;
8194 if (board_config == ALC883_AUTO)
8195 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02008196#ifdef CONFIG_SND_HDA_POWER_SAVE
8197 if (!spec->loopback.amplist)
8198 spec->loopback.amplist = alc883_loopbacks;
8199#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008200
8201 return 0;
8202}
8203
8204/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008205 * ALC262 support
8206 */
8207
8208#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8209#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8210
8211#define alc262_dac_nids alc260_dac_nids
8212#define alc262_adc_nids alc882_adc_nids
8213#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008214#define alc262_capsrc_nids alc882_capsrc_nids
8215#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008216
8217#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008218#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008219
8220static struct snd_kcontrol_new alc262_base_mixer[] = {
8221 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8222 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8223 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8224 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8225 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8226 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8227 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8228 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008229 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008230 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8231 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008232 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008233 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008234 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008235 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8236 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8237 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8238 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008239 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008240};
8241
Kailang Yangccc656c2006-10-17 12:32:26 +02008242static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8243 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8244 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8245 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8246 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8247 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8248 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8249 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8250 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008251 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008252 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8253 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008254 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008255 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008256 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008257 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8258 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8259 { } /* end */
8260};
8261
Takashi Iwaice875f02008-01-28 18:17:43 +01008262/* update HP, line and mono-out pins according to the master switch */
8263static void alc262_hp_master_update(struct hda_codec *codec)
8264{
8265 struct alc_spec *spec = codec->spec;
8266 int val = spec->master_sw;
8267
8268 /* HP & line-out */
8269 snd_hda_codec_write_cache(codec, 0x1b, 0,
8270 AC_VERB_SET_PIN_WIDGET_CONTROL,
8271 val ? PIN_HP : 0);
8272 snd_hda_codec_write_cache(codec, 0x15, 0,
8273 AC_VERB_SET_PIN_WIDGET_CONTROL,
8274 val ? PIN_HP : 0);
8275 /* mono (speaker) depending on the HP jack sense */
8276 val = val && !spec->jack_present;
8277 snd_hda_codec_write_cache(codec, 0x16, 0,
8278 AC_VERB_SET_PIN_WIDGET_CONTROL,
8279 val ? PIN_OUT : 0);
8280}
8281
8282static void alc262_hp_bpc_automute(struct hda_codec *codec)
8283{
8284 struct alc_spec *spec = codec->spec;
8285 unsigned int presence;
8286 presence = snd_hda_codec_read(codec, 0x1b, 0,
8287 AC_VERB_GET_PIN_SENSE, 0);
8288 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8289 alc262_hp_master_update(codec);
8290}
8291
8292static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8293{
8294 if ((res >> 26) != ALC880_HP_EVENT)
8295 return;
8296 alc262_hp_bpc_automute(codec);
8297}
8298
8299static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8300{
8301 struct alc_spec *spec = codec->spec;
8302 unsigned int presence;
8303 presence = snd_hda_codec_read(codec, 0x15, 0,
8304 AC_VERB_GET_PIN_SENSE, 0);
8305 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8306 alc262_hp_master_update(codec);
8307}
8308
8309static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8310 unsigned int res)
8311{
8312 if ((res >> 26) != ALC880_HP_EVENT)
8313 return;
8314 alc262_hp_wildwest_automute(codec);
8315}
8316
8317static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8318 struct snd_ctl_elem_value *ucontrol)
8319{
8320 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8321 struct alc_spec *spec = codec->spec;
8322 *ucontrol->value.integer.value = spec->master_sw;
8323 return 0;
8324}
8325
8326static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8327 struct snd_ctl_elem_value *ucontrol)
8328{
8329 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8330 struct alc_spec *spec = codec->spec;
8331 int val = !!*ucontrol->value.integer.value;
8332
8333 if (val == spec->master_sw)
8334 return 0;
8335 spec->master_sw = val;
8336 alc262_hp_master_update(codec);
8337 return 1;
8338}
8339
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008340static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008341 {
8342 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8343 .name = "Master Playback Switch",
8344 .info = snd_ctl_boolean_mono_info,
8345 .get = alc262_hp_master_sw_get,
8346 .put = alc262_hp_master_sw_put,
8347 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008348 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8349 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8350 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008351 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8352 HDA_OUTPUT),
8353 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8354 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008355 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8356 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008357 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008358 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8359 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008360 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008361 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8362 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8363 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8364 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8365 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8366 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8367 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8368 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8369 { } /* end */
8370};
8371
Kailang Yangcd7509a2007-01-26 18:33:17 +01008372static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008373 {
8374 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8375 .name = "Master Playback Switch",
8376 .info = snd_ctl_boolean_mono_info,
8377 .get = alc262_hp_master_sw_get,
8378 .put = alc262_hp_master_sw_put,
8379 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008380 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8381 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8382 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8383 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008384 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8385 HDA_OUTPUT),
8386 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8387 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008388 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8389 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008390 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008391 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8392 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8393 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8394 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8395 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8396 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8397 { } /* end */
8398};
8399
8400static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8401 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8402 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008403 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008404 { } /* end */
8405};
8406
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008407/* mute/unmute internal speaker according to the hp jack and mute state */
8408static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8409{
8410 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008411
8412 if (force || !spec->sense_updated) {
8413 unsigned int present;
8414 present = snd_hda_codec_read(codec, 0x15, 0,
8415 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008416 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008417 spec->sense_updated = 1;
8418 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008419 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8420 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008421}
8422
8423static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8424 unsigned int res)
8425{
8426 if ((res >> 26) != ALC880_HP_EVENT)
8427 return;
8428 alc262_hp_t5735_automute(codec, 1);
8429}
8430
8431static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8432{
8433 alc262_hp_t5735_automute(codec, 1);
8434}
8435
8436static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008437 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8438 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008439 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8440 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8441 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8442 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8443 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8444 { } /* end */
8445};
8446
8447static struct hda_verb alc262_hp_t5735_verbs[] = {
8448 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8449 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8450
8451 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8452 { }
8453};
8454
Kailang Yang8c427222008-01-10 13:03:59 +01008455static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01008456 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8457 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008458 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8459 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01008460 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8461 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8462 { } /* end */
8463};
8464
8465static struct hda_verb alc262_hp_rp5700_verbs[] = {
8466 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8467 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8468 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8469 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8470 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8471 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8472 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8473 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8474 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8475 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8476 {}
8477};
8478
8479static struct hda_input_mux alc262_hp_rp5700_capture_source = {
8480 .num_items = 1,
8481 .items = {
8482 { "Line", 0x1 },
8483 },
8484};
8485
Takashi Iwai0724ea22007-08-23 00:31:43 +02008486/* bind hp and internal speaker mute (with plug check) */
8487static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
8488 struct snd_ctl_elem_value *ucontrol)
8489{
8490 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8491 long *valp = ucontrol->value.integer.value;
8492 int change;
8493
8494 /* change hp mute */
8495 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
8496 HDA_AMP_MUTE,
8497 valp[0] ? 0 : HDA_AMP_MUTE);
8498 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
8499 HDA_AMP_MUTE,
8500 valp[1] ? 0 : HDA_AMP_MUTE);
8501 if (change) {
8502 /* change speaker according to HP jack state */
8503 struct alc_spec *spec = codec->spec;
8504 unsigned int mute;
8505 if (spec->jack_present)
8506 mute = HDA_AMP_MUTE;
8507 else
8508 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
8509 HDA_OUTPUT, 0);
8510 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8511 HDA_AMP_MUTE, mute);
8512 }
8513 return change;
8514}
Takashi Iwai5b319542007-07-26 11:49:22 +02008515
Kailang Yang272a5272007-05-14 11:00:38 +02008516static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02008517 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8518 {
8519 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8520 .name = "Master Playback Switch",
8521 .info = snd_hda_mixer_amp_switch_info,
8522 .get = snd_hda_mixer_amp_switch_get,
8523 .put = alc262_sony_master_sw_put,
8524 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8525 },
Kailang Yang272a5272007-05-14 11:00:38 +02008526 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8527 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8528 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8529 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8530 { } /* end */
8531};
8532
Kailang Yang83c34212007-07-05 11:43:05 +02008533static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8534 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8535 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8536 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8537 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8538 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8539 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8540 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8541 { } /* end */
8542};
Kailang Yang272a5272007-05-14 11:00:38 +02008543
Kailang Yangdf694da2005-12-05 19:42:22 +01008544#define alc262_capture_mixer alc882_capture_mixer
8545#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8546
8547/*
8548 * generic initialization of ADC, input mixers and output mixers
8549 */
8550static struct hda_verb alc262_init_verbs[] = {
8551 /*
8552 * Unmute ADC0-2 and set the default input to mic-in
8553 */
8554 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8555 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8556 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8557 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8558 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8559 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8560
Takashi Iwaicb53c622007-08-10 17:21:45 +02008561 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008562 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008563 * Note: PASD motherboards uses the Line In 2 as the input for
8564 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008565 */
8566 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008567 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8568 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8569 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8570 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8571 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008572
8573 /*
8574 * Set up output mixers (0x0c - 0x0e)
8575 */
8576 /* set vol=0 to output mixers */
8577 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8578 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8579 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8580 /* set up input amps for analog loopback */
8581 /* Amp Indices: DAC = 0, mixer = 1 */
8582 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8583 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8584 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8585 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8586 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8587 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8588
8589 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8590 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8591 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8592 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8593 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8594 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8595
8596 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8597 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8598 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8599 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8600 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8601
8602 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8603 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8604
8605 /* FIXME: use matrix-type input source selection */
8606 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8607 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8608 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8609 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8610 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8611 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8612 /* Input mixer2 */
8613 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8614 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8615 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8616 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8617 /* Input mixer3 */
8618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008622
8623 { }
8624};
8625
Kailang Yangccc656c2006-10-17 12:32:26 +02008626static struct hda_verb alc262_hippo_unsol_verbs[] = {
8627 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8628 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8629 {}
8630};
8631
8632static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8633 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8634 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8635 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8636
8637 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8638 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8639 {}
8640};
8641
Kailang Yang272a5272007-05-14 11:00:38 +02008642static struct hda_verb alc262_sony_unsol_verbs[] = {
8643 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8644 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8645 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8646
8647 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8648 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09008649 {}
Kailang Yang272a5272007-05-14 11:00:38 +02008650};
8651
Kailang Yangccc656c2006-10-17 12:32:26 +02008652/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008653static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008654{
8655 struct alc_spec *spec = codec->spec;
8656 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008657 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008658
Takashi Iwai5b319542007-07-26 11:49:22 +02008659 /* need to execute and sync at first */
8660 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8661 present = snd_hda_codec_read(codec, 0x15, 0,
8662 AC_VERB_GET_PIN_SENSE, 0);
8663 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008664 if (spec->jack_present) {
8665 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008666 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8667 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008668 } else {
8669 /* unmute internal speaker if necessary */
8670 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008671 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8672 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008673 }
8674}
8675
8676/* unsolicited event for HP jack sensing */
8677static void alc262_hippo_unsol_event(struct hda_codec *codec,
8678 unsigned int res)
8679{
8680 if ((res >> 26) != ALC880_HP_EVENT)
8681 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008682 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008683}
8684
Takashi Iwai5b319542007-07-26 11:49:22 +02008685static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008686{
Kailang Yangccc656c2006-10-17 12:32:26 +02008687 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008688 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008689
Takashi Iwai5b319542007-07-26 11:49:22 +02008690 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8691 present = snd_hda_codec_read(codec, 0x1b, 0,
8692 AC_VERB_GET_PIN_SENSE, 0);
8693 present = (present & 0x80000000) != 0;
8694 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008695 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008696 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8697 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008698 } else {
8699 /* unmute internal speaker if necessary */
8700 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008701 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8702 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008703 }
8704}
8705
8706/* unsolicited event for HP jack sensing */
8707static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8708 unsigned int res)
8709{
8710 if ((res >> 26) != ALC880_HP_EVENT)
8711 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008712 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008713}
8714
Takashi Iwai834be882006-03-01 14:16:17 +01008715/*
8716 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01008717 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
8718 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01008719 */
8720
8721#define ALC_HP_EVENT 0x37
8722
8723static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8724 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8725 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01008726 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8727 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01008728 {}
8729};
8730
Jiang zhe0e31daf2008-03-20 12:12:39 +01008731static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
8732 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8733 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8734 {}
8735};
8736
Takashi Iwai834be882006-03-01 14:16:17 +01008737static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008738 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008739 .items = {
8740 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008741 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008742 { "CD", 0x4 },
8743 },
8744};
8745
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008746static struct hda_input_mux alc262_HP_capture_source = {
8747 .num_items = 5,
8748 .items = {
8749 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008750 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008751 { "Line", 0x2 },
8752 { "CD", 0x4 },
8753 { "AUX IN", 0x6 },
8754 },
8755};
8756
zhejiangaccbe492007-08-31 12:36:05 +02008757static struct hda_input_mux alc262_HP_D7000_capture_source = {
8758 .num_items = 4,
8759 .items = {
8760 { "Mic", 0x0 },
8761 { "Front Mic", 0x2 },
8762 { "Line", 0x1 },
8763 { "CD", 0x4 },
8764 },
8765};
8766
Takashi Iwaiebc7a402008-05-20 09:23:05 +02008767/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01008768static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8769{
8770 struct alc_spec *spec = codec->spec;
8771 unsigned int mute;
8772
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008773 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02008774 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01008775 /* need to execute and sync at first */
8776 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02008777 /* check laptop HP jack */
8778 present = snd_hda_codec_read(codec, 0x14, 0,
8779 AC_VERB_GET_PIN_SENSE, 0);
8780 /* need to execute and sync at first */
8781 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8782 /* check docking HP jack */
8783 present |= snd_hda_codec_read(codec, 0x1b, 0,
8784 AC_VERB_GET_PIN_SENSE, 0);
8785 if (present & AC_PINSENSE_PRESENCE)
8786 spec->jack_present = 1;
8787 else
8788 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01008789 spec->sense_updated = 1;
8790 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02008791 /* unmute internal speaker only if both HPs are unplugged and
8792 * master switch is on
8793 */
8794 if (spec->jack_present)
8795 mute = HDA_AMP_MUTE;
8796 else
Takashi Iwai834be882006-03-01 14:16:17 +01008797 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02008798 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8799 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008800}
8801
8802/* unsolicited event for HP jack sensing */
8803static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8804 unsigned int res)
8805{
8806 if ((res >> 26) != ALC_HP_EVENT)
8807 return;
8808 alc262_fujitsu_automute(codec, 1);
8809}
8810
Takashi Iwaiebc7a402008-05-20 09:23:05 +02008811static void alc262_fujitsu_init_hook(struct hda_codec *codec)
8812{
8813 alc262_fujitsu_automute(codec, 1);
8814}
8815
Takashi Iwai834be882006-03-01 14:16:17 +01008816/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008817static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8818 .ops = &snd_hda_bind_vol,
8819 .values = {
8820 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8821 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8822 0
8823 },
8824};
Takashi Iwai834be882006-03-01 14:16:17 +01008825
Jiang zhe0e31daf2008-03-20 12:12:39 +01008826/* mute/unmute internal speaker according to the hp jack and mute state */
8827static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
8828{
8829 struct alc_spec *spec = codec->spec;
8830 unsigned int mute;
8831
8832 if (force || !spec->sense_updated) {
8833 unsigned int present_int_hp;
8834 /* need to execute and sync at first */
8835 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8836 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
8837 AC_VERB_GET_PIN_SENSE, 0);
8838 spec->jack_present = (present_int_hp & 0x80000000) != 0;
8839 spec->sense_updated = 1;
8840 }
8841 if (spec->jack_present) {
8842 /* mute internal speaker */
8843 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8844 HDA_AMP_MUTE, HDA_AMP_MUTE);
8845 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8846 HDA_AMP_MUTE, HDA_AMP_MUTE);
8847 } else {
8848 /* unmute internal speaker if necessary */
8849 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8850 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8851 HDA_AMP_MUTE, mute);
8852 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8853 HDA_AMP_MUTE, mute);
8854 }
8855}
8856
8857/* unsolicited event for HP jack sensing */
8858static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
8859 unsigned int res)
8860{
8861 if ((res >> 26) != ALC_HP_EVENT)
8862 return;
8863 alc262_lenovo_3000_automute(codec, 1);
8864}
8865
Takashi Iwai834be882006-03-01 14:16:17 +01008866/* bind hp and internal speaker mute (with plug check) */
8867static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8868 struct snd_ctl_elem_value *ucontrol)
8869{
8870 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8871 long *valp = ucontrol->value.integer.value;
8872 int change;
8873
Tony Vroon5d9fab22008-03-14 17:09:18 +01008874 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8875 HDA_AMP_MUTE,
8876 valp ? 0 : HDA_AMP_MUTE);
8877 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8878 HDA_AMP_MUTE,
8879 valp ? 0 : HDA_AMP_MUTE);
8880
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008881 if (change)
8882 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008883 return change;
8884}
8885
8886static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008887 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008888 {
8889 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8890 .name = "Master Playback Switch",
8891 .info = snd_hda_mixer_amp_switch_info,
8892 .get = snd_hda_mixer_amp_switch_get,
8893 .put = alc262_fujitsu_master_sw_put,
8894 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8895 },
8896 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8897 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02008898 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
8899 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008900 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8901 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8902 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008903 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8904 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8905 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008906 { } /* end */
8907};
8908
Jiang zhe0e31daf2008-03-20 12:12:39 +01008909/* bind hp and internal speaker mute (with plug check) */
8910static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
8911 struct snd_ctl_elem_value *ucontrol)
8912{
8913 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8914 long *valp = ucontrol->value.integer.value;
8915 int change;
8916
8917 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8918 HDA_AMP_MUTE,
8919 valp ? 0 : HDA_AMP_MUTE);
8920
8921 if (change)
8922 alc262_lenovo_3000_automute(codec, 0);
8923 return change;
8924}
8925
8926static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
8927 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
8928 {
8929 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8930 .name = "Master Playback Switch",
8931 .info = snd_hda_mixer_amp_switch_info,
8932 .get = snd_hda_mixer_amp_switch_get,
8933 .put = alc262_lenovo_3000_master_sw_put,
8934 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
8935 },
8936 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8937 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8938 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8939 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8940 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8941 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8942 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8943 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8944 { } /* end */
8945};
8946
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008947/* additional init verbs for Benq laptops */
8948static struct hda_verb alc262_EAPD_verbs[] = {
8949 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8950 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8951 {}
8952};
8953
Kailang Yang83c34212007-07-05 11:43:05 +02008954static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8955 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8956 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8957
8958 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8959 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8960 {}
8961};
8962
Tobin Davisf651b502007-10-26 12:40:47 +02008963/* Samsung Q1 Ultra Vista model setup */
8964static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008965 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8966 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02008967 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8968 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8969 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008970 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02008971 { } /* end */
8972};
8973
8974static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008975 /* output mixer */
8976 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8977 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8978 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8979 /* speaker */
8980 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8981 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8982 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8983 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8984 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02008985 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01008986 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8987 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8988 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8989 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8990 /* internal mic */
8991 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8992 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8993 /* ADC, choose mic */
8994 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8995 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8996 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8997 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8998 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8999 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9000 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9001 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9002 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9003 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009004 {}
9005};
9006
Tobin Davisf651b502007-10-26 12:40:47 +02009007/* mute/unmute internal speaker according to the hp jack and mute state */
9008static void alc262_ultra_automute(struct hda_codec *codec)
9009{
9010 struct alc_spec *spec = codec->spec;
9011 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009012
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009013 mute = 0;
9014 /* auto-mute only when HP is used as HP */
9015 if (!spec->cur_mux[0]) {
9016 unsigned int present;
9017 /* need to execute and sync at first */
9018 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9019 present = snd_hda_codec_read(codec, 0x15, 0,
9020 AC_VERB_GET_PIN_SENSE, 0);
9021 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9022 if (spec->jack_present)
9023 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009024 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009025 /* mute/unmute internal speaker */
9026 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9027 HDA_AMP_MUTE, mute);
9028 /* mute/unmute HP */
9029 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9030 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009031}
9032
9033/* unsolicited event for HP jack sensing */
9034static void alc262_ultra_unsol_event(struct hda_codec *codec,
9035 unsigned int res)
9036{
9037 if ((res >> 26) != ALC880_HP_EVENT)
9038 return;
9039 alc262_ultra_automute(codec);
9040}
9041
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009042static struct hda_input_mux alc262_ultra_capture_source = {
9043 .num_items = 2,
9044 .items = {
9045 { "Mic", 0x1 },
9046 { "Headphone", 0x7 },
9047 },
9048};
9049
9050static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9051 struct snd_ctl_elem_value *ucontrol)
9052{
9053 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9054 struct alc_spec *spec = codec->spec;
9055 int ret;
9056
9057 ret = alc882_mux_enum_put(kcontrol, ucontrol);
9058 if (!ret)
9059 return 0;
9060 /* reprogram the HP pin as mic or HP according to the input source */
9061 snd_hda_codec_write_cache(codec, 0x15, 0,
9062 AC_VERB_SET_PIN_WIDGET_CONTROL,
9063 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9064 alc262_ultra_automute(codec); /* mute/unmute HP */
9065 return ret;
9066}
9067
9068static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9069 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9070 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9071 {
9072 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9073 .name = "Capture Source",
9074 .info = alc882_mux_enum_info,
9075 .get = alc882_mux_enum_get,
9076 .put = alc262_ultra_mux_enum_put,
9077 },
9078 { } /* end */
9079};
9080
Kailang Yangdf694da2005-12-05 19:42:22 +01009081/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009082static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9083 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009084{
9085 hda_nid_t nid;
9086 int err;
9087
9088 spec->multiout.num_dacs = 1; /* only use one dac */
9089 spec->multiout.dac_nids = spec->private_dac_nids;
9090 spec->multiout.dac_nids[0] = 2;
9091
9092 nid = cfg->line_out_pins[0];
9093 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009094 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9095 "Front Playback Volume",
9096 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
9097 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009098 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009099 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9100 "Front Playback Switch",
9101 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9102 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009103 return err;
9104 }
9105
Takashi Iwai82bc9552006-03-21 11:24:42 +01009106 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009107 if (nid) {
9108 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009109 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9110 "Speaker Playback Volume",
9111 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9112 HDA_OUTPUT));
9113 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009114 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009115 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9116 "Speaker Playback Switch",
9117 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9118 HDA_OUTPUT));
9119 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009120 return err;
9121 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009122 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9123 "Speaker Playback Switch",
9124 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9125 HDA_OUTPUT));
9126 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009127 return err;
9128 }
9129 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009130 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009131 if (nid) {
9132 /* spec->multiout.hp_nid = 2; */
9133 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009134 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9135 "Headphone Playback Volume",
9136 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9137 HDA_OUTPUT));
9138 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009139 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009140 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9141 "Headphone Playback Switch",
9142 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9143 HDA_OUTPUT));
9144 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009145 return err;
9146 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009147 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9148 "Headphone Playback Switch",
9149 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9150 HDA_OUTPUT));
9151 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009152 return err;
9153 }
9154 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009155 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009156}
9157
9158/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009159#define alc262_auto_create_analog_input_ctls \
9160 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009161
9162/*
9163 * generic initialization of ADC, input mixers and output mixers
9164 */
9165static struct hda_verb alc262_volume_init_verbs[] = {
9166 /*
9167 * Unmute ADC0-2 and set the default input to mic-in
9168 */
9169 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9170 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9171 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9172 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9173 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9174 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9175
Takashi Iwaicb53c622007-08-10 17:21:45 +02009176 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009177 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009178 * Note: PASD motherboards uses the Line In 2 as the input for
9179 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009180 */
9181 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009182 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9183 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9184 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9185 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9186 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009187
9188 /*
9189 * Set up output mixers (0x0c - 0x0f)
9190 */
9191 /* set vol=0 to output mixers */
9192 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9193 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9194 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9195
9196 /* set up input amps for analog loopback */
9197 /* Amp Indices: DAC = 0, mixer = 1 */
9198 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9199 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9200 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9201 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9202 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9203 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9204
9205 /* FIXME: use matrix-type input source selection */
9206 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9207 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9208 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9209 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9210 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9211 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9212 /* Input mixer2 */
9213 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9214 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9215 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9216 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9217 /* Input mixer3 */
9218 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9219 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9220 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9221 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9222
9223 { }
9224};
9225
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009226static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9227 /*
9228 * Unmute ADC0-2 and set the default input to mic-in
9229 */
9230 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9231 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9232 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9233 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9234 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9235 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9236
Takashi Iwaicb53c622007-08-10 17:21:45 +02009237 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009238 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009239 * Note: PASD motherboards uses the Line In 2 as the input for
9240 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009241 */
9242 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009243 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9244 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9245 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9246 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9247 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009250
9251 /*
9252 * Set up output mixers (0x0c - 0x0e)
9253 */
9254 /* set vol=0 to output mixers */
9255 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9256 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9257 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9258
9259 /* set up input amps for analog loopback */
9260 /* Amp Indices: DAC = 0, mixer = 1 */
9261 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9263 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9264 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9265 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9266 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9267
Takashi Iwaice875f02008-01-28 18:17:43 +01009268 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009269 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9270 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9271
9272 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9273 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9274
9275 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9276 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9277
9278 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9279 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9280 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9281 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9282 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9283
9284 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9285 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9286 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9287 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9288 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9289 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9290
9291
9292 /* FIXME: use matrix-type input source selection */
9293 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9294 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9295 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9296 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9297 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9298 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9299 /* Input mixer2 */
9300 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9301 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9302 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9303 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9304 /* Input mixer3 */
9305 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9306 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9307 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9308 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9309
Takashi Iwaice875f02008-01-28 18:17:43 +01009310 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9311
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009312 { }
9313};
9314
Kailang Yangcd7509a2007-01-26 18:33:17 +01009315static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
9316 /*
9317 * Unmute ADC0-2 and set the default input to mic-in
9318 */
9319 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9320 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9321 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9322 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9323 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9324 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9325
Takashi Iwaicb53c622007-08-10 17:21:45 +02009326 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01009327 * mixer widget
9328 * Note: PASD motherboards uses the Line In 2 as the input for front
9329 * panel mic (mic 2)
9330 */
9331 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009332 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9333 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9334 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9335 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9336 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9337 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9338 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9339 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01009340 /*
9341 * Set up output mixers (0x0c - 0x0e)
9342 */
9343 /* set vol=0 to output mixers */
9344 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9345 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9346 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9347
9348 /* set up input amps for analog loopback */
9349 /* Amp Indices: DAC = 0, mixer = 1 */
9350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9351 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9352 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9353 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9354 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9355 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9356
9357
9358 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
9359 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
9360 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
9361 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
9362 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
9363 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
9364 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
9365
9366 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9367 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9368
9369 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9370 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9371
9372 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
9373 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9374 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9375 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9376 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9377 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9378
9379 /* FIXME: use matrix-type input source selection */
9380 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9381 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9382 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
9383 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
9384 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
9385 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
9386 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
9387 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9388 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
9389 /* Input mixer2 */
9390 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9391 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9392 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9393 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9394 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9395 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9396 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9397 /* Input mixer3 */
9398 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9399 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9400 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9401 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9402 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9403 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9404 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9405
Takashi Iwaice875f02008-01-28 18:17:43 +01009406 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9407
Kailang Yangcd7509a2007-01-26 18:33:17 +01009408 { }
9409};
9410
Takashi Iwaicb53c622007-08-10 17:21:45 +02009411#ifdef CONFIG_SND_HDA_POWER_SAVE
9412#define alc262_loopbacks alc880_loopbacks
9413#endif
9414
Kailang Yangdf694da2005-12-05 19:42:22 +01009415/* pcm configuration: identiacal with ALC880 */
9416#define alc262_pcm_analog_playback alc880_pcm_analog_playback
9417#define alc262_pcm_analog_capture alc880_pcm_analog_capture
9418#define alc262_pcm_digital_playback alc880_pcm_digital_playback
9419#define alc262_pcm_digital_capture alc880_pcm_digital_capture
9420
9421/*
9422 * BIOS auto configuration
9423 */
9424static int alc262_parse_auto_config(struct hda_codec *codec)
9425{
9426 struct alc_spec *spec = codec->spec;
9427 int err;
9428 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
9429
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009430 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9431 alc262_ignore);
9432 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009433 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009434 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01009435 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009436 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
9437 if (err < 0)
9438 return err;
9439 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
9440 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009441 return err;
9442
9443 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9444
9445 if (spec->autocfg.dig_out_pin)
9446 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
9447 if (spec->autocfg.dig_in_pin)
9448 spec->dig_in_nid = ALC262_DIGIN_NID;
9449
9450 if (spec->kctl_alloc)
9451 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9452
9453 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02009454 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01009455 spec->input_mux = &spec->private_imux;
9456
Takashi Iwai776e1842007-08-29 15:07:11 +02009457 err = alc_auto_add_mic_boost(codec);
9458 if (err < 0)
9459 return err;
9460
Kailang Yangdf694da2005-12-05 19:42:22 +01009461 return 1;
9462}
9463
9464#define alc262_auto_init_multi_out alc882_auto_init_multi_out
9465#define alc262_auto_init_hp_out alc882_auto_init_hp_out
9466#define alc262_auto_init_analog_input alc882_auto_init_analog_input
9467
9468
9469/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009470static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01009471{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009472 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01009473 alc262_auto_init_multi_out(codec);
9474 alc262_auto_init_hp_out(codec);
9475 alc262_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009476 if (spec->unsol_event)
9477 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01009478}
9479
9480/*
9481 * configuration and preset
9482 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009483static const char *alc262_models[ALC262_MODEL_LAST] = {
9484 [ALC262_BASIC] = "basic",
9485 [ALC262_HIPPO] = "hippo",
9486 [ALC262_HIPPO_1] = "hippo_1",
9487 [ALC262_FUJITSU] = "fujitsu",
9488 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01009489 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01009490 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +01009491 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009492 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02009493 [ALC262_BENQ_T31] = "benq-t31",
9494 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02009495 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +01009496 [ALC262_LENOVO_3000] = "lenovo-3000",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009497 [ALC262_AUTO] = "auto",
9498};
9499
9500static struct snd_pci_quirk alc262_cfg_tbl[] = {
9501 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
9502 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009503 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009504 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
9505 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009506 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009507 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009508 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009509 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009510 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009511 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009512 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009513 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009514 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009515 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009516 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009517 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009518 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
9519 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
9520 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009521 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
9522 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +01009523 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009524 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009525 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009526 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9527 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9528 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009529 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +01009530 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009531 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009532 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +01009533 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009534 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02009535 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009536 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01009537 {}
9538};
9539
9540static struct alc_config_preset alc262_presets[] = {
9541 [ALC262_BASIC] = {
9542 .mixers = { alc262_base_mixer },
9543 .init_verbs = { alc262_init_verbs },
9544 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9545 .dac_nids = alc262_dac_nids,
9546 .hp_nid = 0x03,
9547 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9548 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01009549 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01009550 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009551 [ALC262_HIPPO] = {
9552 .mixers = { alc262_base_mixer },
9553 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
9554 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9555 .dac_nids = alc262_dac_nids,
9556 .hp_nid = 0x03,
9557 .dig_out_nid = ALC262_DIGOUT_NID,
9558 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9559 .channel_mode = alc262_modes,
9560 .input_mux = &alc262_capture_source,
9561 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009562 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009563 },
9564 [ALC262_HIPPO_1] = {
9565 .mixers = { alc262_hippo1_mixer },
9566 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
9567 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9568 .dac_nids = alc262_dac_nids,
9569 .hp_nid = 0x02,
9570 .dig_out_nid = ALC262_DIGOUT_NID,
9571 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9572 .channel_mode = alc262_modes,
9573 .input_mux = &alc262_capture_source,
9574 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009575 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009576 },
Takashi Iwai834be882006-03-01 14:16:17 +01009577 [ALC262_FUJITSU] = {
9578 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009579 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9580 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01009581 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9582 .dac_nids = alc262_dac_nids,
9583 .hp_nid = 0x03,
9584 .dig_out_nid = ALC262_DIGOUT_NID,
9585 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9586 .channel_mode = alc262_modes,
9587 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009588 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009589 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +01009590 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009591 [ALC262_HP_BPC] = {
9592 .mixers = { alc262_HP_BPC_mixer },
9593 .init_verbs = { alc262_HP_BPC_init_verbs },
9594 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9595 .dac_nids = alc262_dac_nids,
9596 .hp_nid = 0x03,
9597 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9598 .channel_mode = alc262_modes,
9599 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009600 .unsol_event = alc262_hp_bpc_unsol_event,
9601 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009602 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009603 [ALC262_HP_BPC_D7000_WF] = {
9604 .mixers = { alc262_HP_BPC_WildWest_mixer },
9605 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9606 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9607 .dac_nids = alc262_dac_nids,
9608 .hp_nid = 0x03,
9609 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9610 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009611 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009612 .unsol_event = alc262_hp_wildwest_unsol_event,
9613 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009614 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009615 [ALC262_HP_BPC_D7000_WL] = {
9616 .mixers = { alc262_HP_BPC_WildWest_mixer,
9617 alc262_HP_BPC_WildWest_option_mixer },
9618 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9619 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9620 .dac_nids = alc262_dac_nids,
9621 .hp_nid = 0x03,
9622 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9623 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009624 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009625 .unsol_event = alc262_hp_wildwest_unsol_event,
9626 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009627 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009628 [ALC262_HP_TC_T5735] = {
9629 .mixers = { alc262_hp_t5735_mixer },
9630 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
9631 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9632 .dac_nids = alc262_dac_nids,
9633 .hp_nid = 0x03,
9634 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9635 .channel_mode = alc262_modes,
9636 .input_mux = &alc262_capture_source,
9637 .unsol_event = alc262_hp_t5735_unsol_event,
9638 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +01009639 },
9640 [ALC262_HP_RP5700] = {
9641 .mixers = { alc262_hp_rp5700_mixer },
9642 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
9643 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9644 .dac_nids = alc262_dac_nids,
9645 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9646 .channel_mode = alc262_modes,
9647 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009648 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009649 [ALC262_BENQ_ED8] = {
9650 .mixers = { alc262_base_mixer },
9651 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
9652 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9653 .dac_nids = alc262_dac_nids,
9654 .hp_nid = 0x03,
9655 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9656 .channel_mode = alc262_modes,
9657 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009658 },
Kailang Yang272a5272007-05-14 11:00:38 +02009659 [ALC262_SONY_ASSAMD] = {
9660 .mixers = { alc262_sony_mixer },
9661 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
9662 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9663 .dac_nids = alc262_dac_nids,
9664 .hp_nid = 0x02,
9665 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9666 .channel_mode = alc262_modes,
9667 .input_mux = &alc262_capture_source,
9668 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009669 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02009670 },
9671 [ALC262_BENQ_T31] = {
9672 .mixers = { alc262_benq_t31_mixer },
9673 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
9674 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9675 .dac_nids = alc262_dac_nids,
9676 .hp_nid = 0x03,
9677 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9678 .channel_mode = alc262_modes,
9679 .input_mux = &alc262_capture_source,
9680 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009681 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02009682 },
Tobin Davisf651b502007-10-26 12:40:47 +02009683 [ALC262_ULTRA] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009684 .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
9685 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +02009686 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9687 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +02009688 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9689 .channel_mode = alc262_modes,
9690 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009691 .adc_nids = alc262_adc_nids, /* ADC0 */
9692 .capsrc_nids = alc262_capsrc_nids,
9693 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +02009694 .unsol_event = alc262_ultra_unsol_event,
9695 .init_hook = alc262_ultra_automute,
9696 },
Jiang zhe0e31daf2008-03-20 12:12:39 +01009697 [ALC262_LENOVO_3000] = {
9698 .mixers = { alc262_lenovo_3000_mixer },
9699 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9700 alc262_lenovo_3000_unsol_verbs },
9701 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9702 .dac_nids = alc262_dac_nids,
9703 .hp_nid = 0x03,
9704 .dig_out_nid = ALC262_DIGOUT_NID,
9705 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9706 .channel_mode = alc262_modes,
9707 .input_mux = &alc262_fujitsu_capture_source,
9708 .unsol_event = alc262_lenovo_3000_unsol_event,
9709 },
Kailang Yangdf694da2005-12-05 19:42:22 +01009710};
9711
9712static int patch_alc262(struct hda_codec *codec)
9713{
9714 struct alc_spec *spec;
9715 int board_config;
9716 int err;
9717
Robert P. J. Daydc041e02006-12-19 14:44:15 +01009718 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01009719 if (spec == NULL)
9720 return -ENOMEM;
9721
9722 codec->spec = spec;
9723#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009724 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
9725 * under-run
9726 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009727 {
9728 int tmp;
9729 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9730 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
9731 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9732 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9733 }
9734#endif
9735
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009736 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9737 alc262_models,
9738 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009739
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009740 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009741 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9742 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009743 board_config = ALC262_AUTO;
9744 }
9745
9746 if (board_config == ALC262_AUTO) {
9747 /* automatic parse from the BIOS config */
9748 err = alc262_parse_auto_config(codec);
9749 if (err < 0) {
9750 alc_free(codec);
9751 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009752 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009753 printk(KERN_INFO
9754 "hda_codec: Cannot set up configuration "
9755 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009756 board_config = ALC262_BASIC;
9757 }
9758 }
9759
9760 if (board_config != ALC262_AUTO)
9761 setup_preset(spec, &alc262_presets[board_config]);
9762
9763 spec->stream_name_analog = "ALC262 Analog";
9764 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9765 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9766
9767 spec->stream_name_digital = "ALC262 Digital";
9768 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9769 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9770
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009771 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009772 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009773 unsigned int wcap = get_wcaps(codec, 0x07);
9774
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009775 /* get type */
9776 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009777 if (wcap != AC_WID_AUD_IN) {
9778 spec->adc_nids = alc262_adc_nids_alt;
9779 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +01009780 spec->capsrc_nids = alc262_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009781 spec->mixers[spec->num_mixers] =
9782 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009783 spec->num_mixers++;
9784 } else {
9785 spec->adc_nids = alc262_adc_nids;
9786 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +01009787 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01009788 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9789 spec->num_mixers++;
9790 }
9791 }
9792
Takashi Iwai2134ea42008-01-10 16:53:55 +01009793 spec->vmaster_nid = 0x0c;
9794
Kailang Yangdf694da2005-12-05 19:42:22 +01009795 codec->patch_ops = alc_patch_ops;
9796 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009797 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009798#ifdef CONFIG_SND_HDA_POWER_SAVE
9799 if (!spec->loopback.amplist)
9800 spec->loopback.amplist = alc262_loopbacks;
9801#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009802
Kailang Yangdf694da2005-12-05 19:42:22 +01009803 return 0;
9804}
9805
Kailang Yangdf694da2005-12-05 19:42:22 +01009806/*
Kailang Yanga361d842007-06-05 12:30:55 +02009807 * ALC268 channel source setting (2 channel)
9808 */
9809#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9810#define alc268_modes alc260_modes
9811
9812static hda_nid_t alc268_dac_nids[2] = {
9813 /* front, hp */
9814 0x02, 0x03
9815};
9816
9817static hda_nid_t alc268_adc_nids[2] = {
9818 /* ADC0-1 */
9819 0x08, 0x07
9820};
9821
9822static hda_nid_t alc268_adc_nids_alt[1] = {
9823 /* ADC0 */
9824 0x08
9825};
9826
Takashi Iwaie1406342008-02-11 18:32:32 +01009827static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
9828
Kailang Yanga361d842007-06-05 12:30:55 +02009829static struct snd_kcontrol_new alc268_base_mixer[] = {
9830 /* output mixer control */
9831 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9832 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9833 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9834 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009835 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9836 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9837 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009838 { }
9839};
9840
Takashi Iwaiaef9d312008-02-19 13:16:41 +01009841/* bind Beep switches of both NID 0x0f and 0x10 */
9842static struct hda_bind_ctls alc268_bind_beep_sw = {
9843 .ops = &snd_hda_bind_sw,
9844 .values = {
9845 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
9846 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
9847 0
9848 },
9849};
9850
9851static struct snd_kcontrol_new alc268_beep_mixer[] = {
9852 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
9853 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
9854 { }
9855};
9856
Kailang Yangd1a991a2007-08-15 16:21:59 +02009857static struct hda_verb alc268_eapd_verbs[] = {
9858 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9859 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9860 { }
9861};
9862
Takashi Iwaid2738092007-08-16 14:59:45 +02009863/* Toshiba specific */
9864#define alc268_toshiba_automute alc262_hippo_automute
9865
9866static struct hda_verb alc268_toshiba_verbs[] = {
9867 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9868 { } /* end */
9869};
9870
9871/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009872/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009873static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9874 .ops = &snd_hda_bind_vol,
9875 .values = {
9876 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9877 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9878 0
9879 },
9880};
9881
Takashi Iwai889c4392007-08-23 18:56:52 +02009882/* mute/unmute internal speaker according to the hp jack and mute state */
9883static void alc268_acer_automute(struct hda_codec *codec, int force)
9884{
9885 struct alc_spec *spec = codec->spec;
9886 unsigned int mute;
9887
9888 if (force || !spec->sense_updated) {
9889 unsigned int present;
9890 present = snd_hda_codec_read(codec, 0x14, 0,
9891 AC_VERB_GET_PIN_SENSE, 0);
9892 spec->jack_present = (present & 0x80000000) != 0;
9893 spec->sense_updated = 1;
9894 }
9895 if (spec->jack_present)
9896 mute = HDA_AMP_MUTE; /* mute internal speaker */
9897 else /* unmute internal speaker if necessary */
9898 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9899 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9900 HDA_AMP_MUTE, mute);
9901}
9902
9903
9904/* bind hp and internal speaker mute (with plug check) */
9905static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9906 struct snd_ctl_elem_value *ucontrol)
9907{
9908 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9909 long *valp = ucontrol->value.integer.value;
9910 int change;
9911
9912 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9913 HDA_AMP_MUTE,
9914 valp[0] ? 0 : HDA_AMP_MUTE);
9915 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9916 HDA_AMP_MUTE,
9917 valp[1] ? 0 : HDA_AMP_MUTE);
9918 if (change)
9919 alc268_acer_automute(codec, 0);
9920 return change;
9921}
Takashi Iwaid2738092007-08-16 14:59:45 +02009922
9923static struct snd_kcontrol_new alc268_acer_mixer[] = {
9924 /* output mixer control */
9925 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9926 {
9927 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9928 .name = "Master Playback Switch",
9929 .info = snd_hda_mixer_amp_switch_info,
9930 .get = snd_hda_mixer_amp_switch_get,
9931 .put = alc268_acer_master_sw_put,
9932 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9933 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009934 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9935 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9936 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009937 { }
9938};
9939
9940static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +01009941 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
9942 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +02009943 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9944 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +01009945 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9946 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +02009947
9948 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9949 { }
9950};
9951
9952/* unsolicited event for HP jack sensing */
9953static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9954 unsigned int res)
9955{
Takashi Iwai889c4392007-08-23 18:56:52 +02009956 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009957 return;
9958 alc268_toshiba_automute(codec);
9959}
9960
9961static void alc268_acer_unsol_event(struct hda_codec *codec,
9962 unsigned int res)
9963{
Takashi Iwai889c4392007-08-23 18:56:52 +02009964 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009965 return;
9966 alc268_acer_automute(codec, 1);
9967}
9968
Takashi Iwai889c4392007-08-23 18:56:52 +02009969static void alc268_acer_init_hook(struct hda_codec *codec)
9970{
9971 alc268_acer_automute(codec, 1);
9972}
9973
Takashi Iwai3866f0b2008-01-15 12:37:42 +01009974static struct snd_kcontrol_new alc268_dell_mixer[] = {
9975 /* output mixer control */
9976 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9977 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9978 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9979 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9980 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9981 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9982 { }
9983};
9984
9985static struct hda_verb alc268_dell_verbs[] = {
9986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9987 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9988 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9989 { }
9990};
9991
9992/* mute/unmute internal speaker according to the hp jack and mute state */
9993static void alc268_dell_automute(struct hda_codec *codec)
9994{
9995 unsigned int present;
9996 unsigned int mute;
9997
9998 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
9999 if (present & 0x80000000)
10000 mute = HDA_AMP_MUTE;
10001 else
10002 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
10003 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10004 HDA_AMP_MUTE, mute);
10005}
10006
10007static void alc268_dell_unsol_event(struct hda_codec *codec,
10008 unsigned int res)
10009{
10010 if ((res >> 26) != ALC880_HP_EVENT)
10011 return;
10012 alc268_dell_automute(codec);
10013}
10014
10015#define alc268_dell_init_hook alc268_dell_automute
10016
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010017static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
10018 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10019 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10020 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10021 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10022 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10023 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
10024 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
10025 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10026 { }
10027};
10028
10029static struct hda_verb alc267_quanta_il1_verbs[] = {
10030 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10031 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
10032 { }
10033};
10034
10035static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
10036{
10037 unsigned int present;
10038
10039 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
10040 & AC_PINSENSE_PRESENCE;
10041 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10042 present ? 0 : PIN_OUT);
10043}
10044
10045static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
10046{
10047 unsigned int present;
10048
10049 present = snd_hda_codec_read(codec, 0x18, 0,
10050 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10051 snd_hda_codec_write(codec, 0x23, 0,
10052 AC_VERB_SET_CONNECT_SEL,
10053 present ? 0x00 : 0x01);
10054}
10055
10056static void alc267_quanta_il1_automute(struct hda_codec *codec)
10057{
10058 alc267_quanta_il1_hp_automute(codec);
10059 alc267_quanta_il1_mic_automute(codec);
10060}
10061
10062static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
10063 unsigned int res)
10064{
10065 switch (res >> 26) {
10066 case ALC880_HP_EVENT:
10067 alc267_quanta_il1_hp_automute(codec);
10068 break;
10069 case ALC880_MIC_EVENT:
10070 alc267_quanta_il1_mic_automute(codec);
10071 break;
10072 }
10073}
10074
Kailang Yanga361d842007-06-05 12:30:55 +020010075/*
10076 * generic initialization of ADC, input mixers and output mixers
10077 */
10078static struct hda_verb alc268_base_init_verbs[] = {
10079 /* Unmute DAC0-1 and set vol = 0 */
10080 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10081 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10082 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10083 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10084 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10085 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10086
10087 /*
10088 * Set up output mixers (0x0c - 0x0e)
10089 */
10090 /* set vol=0 to output mixers */
10091 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10092 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10093 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10094 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
10095
10096 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10097 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10098
10099 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10100 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10101 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10102 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10103 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10104 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10105 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10106 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10107
10108 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10109 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10110 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10111 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10112 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10113 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10114 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010115
10116 /* set PCBEEP vol = 0, mute connections */
10117 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10118 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10119 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010120
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010121 /* Unmute Selector 23h,24h and set the default input to mic-in */
10122
10123 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10124 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10125 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
10126 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020010127
Kailang Yanga361d842007-06-05 12:30:55 +020010128 { }
10129};
10130
10131/*
10132 * generic initialization of ADC, input mixers and output mixers
10133 */
10134static struct hda_verb alc268_volume_init_verbs[] = {
10135 /* set output DAC */
10136 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10137 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10138 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10139 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10140
10141 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10142 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10143 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10144 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10145 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10146
10147 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10148 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10149 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10150 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10151 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10152
10153 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10154 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10155 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10156 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10157
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010158 /* set PCBEEP vol = 0, mute connections */
10159 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10160 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10161 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010162
10163 { }
10164};
10165
10166#define alc268_mux_enum_info alc_mux_enum_info
10167#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010010168#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +020010169
10170static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
10171 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10172 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
10173 {
10174 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10175 /* The multiple "Capture Source" controls confuse alsamixer
10176 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020010177 */
10178 /* .name = "Capture Source", */
10179 .name = "Input Source",
10180 .count = 1,
10181 .info = alc268_mux_enum_info,
10182 .get = alc268_mux_enum_get,
10183 .put = alc268_mux_enum_put,
10184 },
10185 { } /* end */
10186};
10187
10188static struct snd_kcontrol_new alc268_capture_mixer[] = {
10189 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10190 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
10191 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
10192 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
10193 {
10194 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10195 /* The multiple "Capture Source" controls confuse alsamixer
10196 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020010197 */
10198 /* .name = "Capture Source", */
10199 .name = "Input Source",
10200 .count = 2,
10201 .info = alc268_mux_enum_info,
10202 .get = alc268_mux_enum_get,
10203 .put = alc268_mux_enum_put,
10204 },
10205 { } /* end */
10206};
10207
10208static struct hda_input_mux alc268_capture_source = {
10209 .num_items = 4,
10210 .items = {
10211 { "Mic", 0x0 },
10212 { "Front Mic", 0x1 },
10213 { "Line", 0x2 },
10214 { "CD", 0x3 },
10215 },
10216};
10217
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010218static struct hda_input_mux alc268_acer_capture_source = {
10219 .num_items = 3,
10220 .items = {
10221 { "Mic", 0x0 },
10222 { "Internal Mic", 0x6 },
10223 { "Line", 0x2 },
10224 },
10225};
10226
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010227#ifdef CONFIG_SND_DEBUG
10228static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010229 /* Volume widgets */
10230 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10231 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10232 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
10233 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
10234 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
10235 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
10236 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
10237 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
10238 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
10239 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
10240 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
10241 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
10242 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010010243 /* The below appears problematic on some hardwares */
10244 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010245 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10246 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
10247 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
10248 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
10249
10250 /* Modes for retasking pin widgets */
10251 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
10252 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
10253 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
10254 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
10255
10256 /* Controls for GPIO pins, assuming they are configured as outputs */
10257 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
10258 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
10259 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
10260 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
10261
10262 /* Switches to allow the digital SPDIF output pin to be enabled.
10263 * The ALC268 does not have an SPDIF input.
10264 */
10265 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
10266
10267 /* A switch allowing EAPD to be enabled. Some laptops seem to use
10268 * this output to turn on an external amplifier.
10269 */
10270 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
10271 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
10272
10273 { } /* end */
10274};
10275#endif
10276
Kailang Yanga361d842007-06-05 12:30:55 +020010277/* create input playback/capture controls for the given pin */
10278static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
10279 const char *ctlname, int idx)
10280{
10281 char name[32];
10282 int err;
10283
10284 sprintf(name, "%s Playback Volume", ctlname);
10285 if (nid == 0x14) {
10286 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
10287 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
10288 HDA_OUTPUT));
10289 if (err < 0)
10290 return err;
10291 } else if (nid == 0x15) {
10292 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
10293 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
10294 HDA_OUTPUT));
10295 if (err < 0)
10296 return err;
10297 } else
10298 return -1;
10299 sprintf(name, "%s Playback Switch", ctlname);
10300 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
10301 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
10302 if (err < 0)
10303 return err;
10304 return 0;
10305}
10306
10307/* add playback controls from the parsed DAC table */
10308static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
10309 const struct auto_pin_cfg *cfg)
10310{
10311 hda_nid_t nid;
10312 int err;
10313
10314 spec->multiout.num_dacs = 2; /* only use one dac */
10315 spec->multiout.dac_nids = spec->private_dac_nids;
10316 spec->multiout.dac_nids[0] = 2;
10317 spec->multiout.dac_nids[1] = 3;
10318
10319 nid = cfg->line_out_pins[0];
10320 if (nid)
10321 alc268_new_analog_output(spec, nid, "Front", 0);
10322
10323 nid = cfg->speaker_pins[0];
10324 if (nid == 0x1d) {
10325 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10326 "Speaker Playback Volume",
10327 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10328 if (err < 0)
10329 return err;
10330 }
10331 nid = cfg->hp_pins[0];
10332 if (nid)
10333 alc268_new_analog_output(spec, nid, "Headphone", 0);
10334
10335 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
10336 if (nid == 0x16) {
10337 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10338 "Mono Playback Switch",
10339 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
10340 if (err < 0)
10341 return err;
10342 }
10343 return 0;
10344}
10345
10346/* create playback/capture controls for input pins */
10347static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
10348 const struct auto_pin_cfg *cfg)
10349{
10350 struct hda_input_mux *imux = &spec->private_imux;
10351 int i, idx1;
10352
10353 for (i = 0; i < AUTO_PIN_LAST; i++) {
10354 switch(cfg->input_pins[i]) {
10355 case 0x18:
10356 idx1 = 0; /* Mic 1 */
10357 break;
10358 case 0x19:
10359 idx1 = 1; /* Mic 2 */
10360 break;
10361 case 0x1a:
10362 idx1 = 2; /* Line In */
10363 break;
10364 case 0x1c:
10365 idx1 = 3; /* CD */
10366 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010010367 case 0x12:
10368 case 0x13:
10369 idx1 = 6; /* digital mics */
10370 break;
Kailang Yanga361d842007-06-05 12:30:55 +020010371 default:
10372 continue;
10373 }
10374 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
10375 imux->items[imux->num_items].index = idx1;
10376 imux->num_items++;
10377 }
10378 return 0;
10379}
10380
10381static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
10382{
10383 struct alc_spec *spec = codec->spec;
10384 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10385 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10386 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10387 unsigned int dac_vol1, dac_vol2;
10388
10389 if (speaker_nid) {
10390 snd_hda_codec_write(codec, speaker_nid, 0,
10391 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
10392 snd_hda_codec_write(codec, 0x0f, 0,
10393 AC_VERB_SET_AMP_GAIN_MUTE,
10394 AMP_IN_UNMUTE(1));
10395 snd_hda_codec_write(codec, 0x10, 0,
10396 AC_VERB_SET_AMP_GAIN_MUTE,
10397 AMP_IN_UNMUTE(1));
10398 } else {
10399 snd_hda_codec_write(codec, 0x0f, 0,
10400 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
10401 snd_hda_codec_write(codec, 0x10, 0,
10402 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
10403 }
10404
10405 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
10406 if (line_nid == 0x14)
10407 dac_vol2 = AMP_OUT_ZERO;
10408 else if (line_nid == 0x15)
10409 dac_vol1 = AMP_OUT_ZERO;
10410 if (hp_nid == 0x14)
10411 dac_vol2 = AMP_OUT_ZERO;
10412 else if (hp_nid == 0x15)
10413 dac_vol1 = AMP_OUT_ZERO;
10414 if (line_nid != 0x16 || hp_nid != 0x16 ||
10415 spec->autocfg.line_out_pins[1] != 0x16 ||
10416 spec->autocfg.line_out_pins[2] != 0x16)
10417 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
10418
10419 snd_hda_codec_write(codec, 0x02, 0,
10420 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
10421 snd_hda_codec_write(codec, 0x03, 0,
10422 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
10423}
10424
10425/* pcm configuration: identiacal with ALC880 */
10426#define alc268_pcm_analog_playback alc880_pcm_analog_playback
10427#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010010428#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020010429#define alc268_pcm_digital_playback alc880_pcm_digital_playback
10430
10431/*
10432 * BIOS auto configuration
10433 */
10434static int alc268_parse_auto_config(struct hda_codec *codec)
10435{
10436 struct alc_spec *spec = codec->spec;
10437 int err;
10438 static hda_nid_t alc268_ignore[] = { 0 };
10439
10440 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10441 alc268_ignore);
10442 if (err < 0)
10443 return err;
10444 if (!spec->autocfg.line_outs)
10445 return 0; /* can't find valid BIOS pin config */
10446
10447 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
10448 if (err < 0)
10449 return err;
10450 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
10451 if (err < 0)
10452 return err;
10453
10454 spec->multiout.max_channels = 2;
10455
10456 /* digital only support output */
10457 if (spec->autocfg.dig_out_pin)
10458 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
10459
10460 if (spec->kctl_alloc)
10461 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10462
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010463 if (spec->autocfg.speaker_pins[0] != 0x1d)
10464 spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
10465
Kailang Yanga361d842007-06-05 12:30:55 +020010466 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
10467 spec->num_mux_defs = 1;
10468 spec->input_mux = &spec->private_imux;
10469
Takashi Iwai776e1842007-08-29 15:07:11 +020010470 err = alc_auto_add_mic_boost(codec);
10471 if (err < 0)
10472 return err;
10473
Kailang Yanga361d842007-06-05 12:30:55 +020010474 return 1;
10475}
10476
10477#define alc268_auto_init_multi_out alc882_auto_init_multi_out
10478#define alc268_auto_init_hp_out alc882_auto_init_hp_out
10479#define alc268_auto_init_analog_input alc882_auto_init_analog_input
10480
10481/* init callback for auto-configuration model -- overriding the default init */
10482static void alc268_auto_init(struct hda_codec *codec)
10483{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010484 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020010485 alc268_auto_init_multi_out(codec);
10486 alc268_auto_init_hp_out(codec);
10487 alc268_auto_init_mono_speaker_out(codec);
10488 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010489 if (spec->unsol_event)
10490 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020010491}
10492
10493/*
10494 * configuration and preset
10495 */
10496static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010497 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020010498 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020010499 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020010500 [ALC268_ACER] = "acer",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010501 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010502 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010503#ifdef CONFIG_SND_DEBUG
10504 [ALC268_TEST] = "test",
10505#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010506 [ALC268_AUTO] = "auto",
10507};
10508
10509static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020010510 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010511 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010010512 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010513 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010010514 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010515 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010516 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020010517 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020010518 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020010519 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020010520 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020010521 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010522 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010523 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020010524 {}
10525};
10526
10527static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010528 [ALC267_QUANTA_IL1] = {
10529 .mixers = { alc267_quanta_il1_mixer },
10530 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10531 alc267_quanta_il1_verbs },
10532 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10533 .dac_nids = alc268_dac_nids,
10534 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10535 .adc_nids = alc268_adc_nids_alt,
10536 .hp_nid = 0x03,
10537 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10538 .channel_mode = alc268_modes,
10539 .input_mux = &alc268_capture_source,
10540 .unsol_event = alc267_quanta_il1_unsol_event,
10541 .init_hook = alc267_quanta_il1_automute,
10542 },
Kailang Yanga361d842007-06-05 12:30:55 +020010543 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010544 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10545 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020010546 .init_verbs = { alc268_base_init_verbs },
10547 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10548 .dac_nids = alc268_dac_nids,
10549 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10550 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010551 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020010552 .hp_nid = 0x03,
10553 .dig_out_nid = ALC268_DIGOUT_NID,
10554 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10555 .channel_mode = alc268_modes,
10556 .input_mux = &alc268_capture_source,
10557 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010558 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010559 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10560 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010561 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10562 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010563 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10564 .dac_nids = alc268_dac_nids,
10565 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10566 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010567 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010568 .hp_nid = 0x03,
10569 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10570 .channel_mode = alc268_modes,
10571 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010572 .unsol_event = alc268_toshiba_unsol_event,
10573 .init_hook = alc268_toshiba_automute,
10574 },
10575 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010576 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
10577 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010578 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10579 alc268_acer_verbs },
10580 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10581 .dac_nids = alc268_dac_nids,
10582 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10583 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010584 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020010585 .hp_nid = 0x02,
10586 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10587 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010588 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010589 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020010590 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010591 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010592 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010593 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010594 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10595 alc268_dell_verbs },
10596 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10597 .dac_nids = alc268_dac_nids,
10598 .hp_nid = 0x02,
10599 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10600 .channel_mode = alc268_modes,
10601 .unsol_event = alc268_dell_unsol_event,
10602 .init_hook = alc268_dell_init_hook,
10603 .input_mux = &alc268_capture_source,
10604 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010605 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010606 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
10607 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010608 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10609 alc268_toshiba_verbs },
10610 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10611 .dac_nids = alc268_dac_nids,
10612 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10613 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010614 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010615 .hp_nid = 0x03,
10616 .dig_out_nid = ALC268_DIGOUT_NID,
10617 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10618 .channel_mode = alc268_modes,
10619 .input_mux = &alc268_capture_source,
10620 .unsol_event = alc268_toshiba_unsol_event,
10621 .init_hook = alc268_toshiba_automute
10622 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010623#ifdef CONFIG_SND_DEBUG
10624 [ALC268_TEST] = {
10625 .mixers = { alc268_test_mixer, alc268_capture_mixer },
10626 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10627 alc268_volume_init_verbs },
10628 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10629 .dac_nids = alc268_dac_nids,
10630 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10631 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010632 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010633 .hp_nid = 0x03,
10634 .dig_out_nid = ALC268_DIGOUT_NID,
10635 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10636 .channel_mode = alc268_modes,
10637 .input_mux = &alc268_capture_source,
10638 },
10639#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010640};
10641
10642static int patch_alc268(struct hda_codec *codec)
10643{
10644 struct alc_spec *spec;
10645 int board_config;
10646 int err;
10647
10648 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
10649 if (spec == NULL)
10650 return -ENOMEM;
10651
10652 codec->spec = spec;
10653
10654 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
10655 alc268_models,
10656 alc268_cfg_tbl);
10657
10658 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
10659 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
10660 "trying auto-probe from BIOS...\n");
10661 board_config = ALC268_AUTO;
10662 }
10663
10664 if (board_config == ALC268_AUTO) {
10665 /* automatic parse from the BIOS config */
10666 err = alc268_parse_auto_config(codec);
10667 if (err < 0) {
10668 alc_free(codec);
10669 return err;
10670 } else if (!err) {
10671 printk(KERN_INFO
10672 "hda_codec: Cannot set up configuration "
10673 "from BIOS. Using base mode...\n");
10674 board_config = ALC268_3ST;
10675 }
10676 }
10677
10678 if (board_config != ALC268_AUTO)
10679 setup_preset(spec, &alc268_presets[board_config]);
10680
10681 spec->stream_name_analog = "ALC268 Analog";
10682 spec->stream_analog_playback = &alc268_pcm_analog_playback;
10683 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010010684 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020010685
10686 spec->stream_name_digital = "ALC268 Digital";
10687 spec->stream_digital_playback = &alc268_pcm_digital_playback;
10688
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010689 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
10690 /* override the amp caps for beep generator */
10691 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
10692 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
10693 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
10694 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
10695 (0 << AC_AMPCAP_MUTE_SHIFT));
10696
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010697 if (!spec->adc_nids && spec->input_mux) {
10698 /* check whether NID 0x07 is valid */
10699 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010010700 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020010701
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010702 /* get type */
10703 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010010704 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010705 spec->adc_nids = alc268_adc_nids_alt;
10706 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
10707 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020010708 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010709 spec->num_mixers++;
10710 } else {
10711 spec->adc_nids = alc268_adc_nids;
10712 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
10713 spec->mixers[spec->num_mixers] =
10714 alc268_capture_mixer;
10715 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020010716 }
Takashi Iwaie1406342008-02-11 18:32:32 +010010717 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010010718 /* set default input source */
10719 for (i = 0; i < spec->num_adc_nids; i++)
10720 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
10721 0, AC_VERB_SET_CONNECT_SEL,
10722 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020010723 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010010724
10725 spec->vmaster_nid = 0x02;
10726
Kailang Yanga361d842007-06-05 12:30:55 +020010727 codec->patch_ops = alc_patch_ops;
10728 if (board_config == ALC268_AUTO)
10729 spec->init_hook = alc268_auto_init;
10730
10731 return 0;
10732}
10733
10734/*
Kailang Yangf6a92242007-12-13 16:52:54 +010010735 * ALC269 channel source setting (2 channel)
10736 */
10737#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
10738
10739#define alc269_dac_nids alc260_dac_nids
10740
10741static hda_nid_t alc269_adc_nids[1] = {
10742 /* ADC1 */
10743 0x07,
10744};
10745
10746#define alc269_modes alc260_modes
10747#define alc269_capture_source alc880_lg_lw_capture_source
10748
10749static struct snd_kcontrol_new alc269_base_mixer[] = {
10750 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10751 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10752 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10753 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10754 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10755 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10756 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10757 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10758 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10759 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10760 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10761 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
10762 { } /* end */
10763};
10764
10765/* capture mixer elements */
10766static struct snd_kcontrol_new alc269_capture_mixer[] = {
10767 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10768 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10769 {
10770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10771 /* The multiple "Capture Source" controls confuse alsamixer
10772 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010010773 */
10774 /* .name = "Capture Source", */
10775 .name = "Input Source",
10776 .count = 1,
10777 .info = alc_mux_enum_info,
10778 .get = alc_mux_enum_get,
10779 .put = alc_mux_enum_put,
10780 },
10781 { } /* end */
10782};
10783
10784/*
10785 * generic initialization of ADC, input mixers and output mixers
10786 */
10787static struct hda_verb alc269_init_verbs[] = {
10788 /*
10789 * Unmute ADC0 and set the default input to mic-in
10790 */
10791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10792
10793 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
10794 * analog-loopback mixer widget
10795 * Note: PASD motherboards uses the Line In 2 as the input for
10796 * front panel mic (mic 2)
10797 */
10798 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
10799 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10800 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10801 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10802 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10803 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10804
10805 /*
10806 * Set up output mixers (0x0c - 0x0e)
10807 */
10808 /* set vol=0 to output mixers */
10809 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10810 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10811
10812 /* set up input amps for analog loopback */
10813 /* Amp Indices: DAC = 0, mixer = 1 */
10814 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10815 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10816 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10817 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10818 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10819 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10820
10821 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10822 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10823 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10824 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10825 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10826 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10827 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10828
10829 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10830 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10831 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10832 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10833 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10835 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10836
10837 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10838 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10839
10840 /* FIXME: use matrix-type input source selection */
10841 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
10842 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10843 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10844 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10845 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10846 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10847
10848 /* set EAPD */
10849 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10850 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10851 { }
10852};
10853
10854/* add playback controls from the parsed DAC table */
10855static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
10856 const struct auto_pin_cfg *cfg)
10857{
10858 hda_nid_t nid;
10859 int err;
10860
10861 spec->multiout.num_dacs = 1; /* only use one dac */
10862 spec->multiout.dac_nids = spec->private_dac_nids;
10863 spec->multiout.dac_nids[0] = 2;
10864
10865 nid = cfg->line_out_pins[0];
10866 if (nid) {
10867 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10868 "Front Playback Volume",
10869 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
10870 if (err < 0)
10871 return err;
10872 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10873 "Front Playback Switch",
10874 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10875 if (err < 0)
10876 return err;
10877 }
10878
10879 nid = cfg->speaker_pins[0];
10880 if (nid) {
10881 if (!cfg->line_out_pins[0]) {
10882 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10883 "Speaker Playback Volume",
10884 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10885 HDA_OUTPUT));
10886 if (err < 0)
10887 return err;
10888 }
10889 if (nid == 0x16) {
10890 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10891 "Speaker Playback Switch",
10892 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10893 HDA_OUTPUT));
10894 if (err < 0)
10895 return err;
10896 } else {
10897 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10898 "Speaker Playback Switch",
10899 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10900 HDA_OUTPUT));
10901 if (err < 0)
10902 return err;
10903 }
10904 }
10905 nid = cfg->hp_pins[0];
10906 if (nid) {
10907 /* spec->multiout.hp_nid = 2; */
10908 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
10909 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10910 "Headphone Playback Volume",
10911 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10912 HDA_OUTPUT));
10913 if (err < 0)
10914 return err;
10915 }
10916 if (nid == 0x16) {
10917 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10918 "Headphone Playback Switch",
10919 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10920 HDA_OUTPUT));
10921 if (err < 0)
10922 return err;
10923 } else {
10924 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10925 "Headphone Playback Switch",
10926 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10927 HDA_OUTPUT));
10928 if (err < 0)
10929 return err;
10930 }
10931 }
10932 return 0;
10933}
10934
10935#define alc269_auto_create_analog_input_ctls \
10936 alc880_auto_create_analog_input_ctls
10937
10938#ifdef CONFIG_SND_HDA_POWER_SAVE
10939#define alc269_loopbacks alc880_loopbacks
10940#endif
10941
10942/* pcm configuration: identiacal with ALC880 */
10943#define alc269_pcm_analog_playback alc880_pcm_analog_playback
10944#define alc269_pcm_analog_capture alc880_pcm_analog_capture
10945#define alc269_pcm_digital_playback alc880_pcm_digital_playback
10946#define alc269_pcm_digital_capture alc880_pcm_digital_capture
10947
10948/*
10949 * BIOS auto configuration
10950 */
10951static int alc269_parse_auto_config(struct hda_codec *codec)
10952{
10953 struct alc_spec *spec = codec->spec;
10954 int err;
10955 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
10956
10957 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10958 alc269_ignore);
10959 if (err < 0)
10960 return err;
10961
10962 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
10963 if (err < 0)
10964 return err;
10965 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
10966 if (err < 0)
10967 return err;
10968
10969 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10970
10971 if (spec->autocfg.dig_out_pin)
10972 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
10973
10974 if (spec->kctl_alloc)
10975 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10976
10977 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
10978 spec->num_mux_defs = 1;
10979 spec->input_mux = &spec->private_imux;
10980
10981 err = alc_auto_add_mic_boost(codec);
10982 if (err < 0)
10983 return err;
10984
10985 return 1;
10986}
10987
10988#define alc269_auto_init_multi_out alc882_auto_init_multi_out
10989#define alc269_auto_init_hp_out alc882_auto_init_hp_out
10990#define alc269_auto_init_analog_input alc882_auto_init_analog_input
10991
10992
10993/* init callback for auto-configuration model -- overriding the default init */
10994static void alc269_auto_init(struct hda_codec *codec)
10995{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010996 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010010997 alc269_auto_init_multi_out(codec);
10998 alc269_auto_init_hp_out(codec);
10999 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011000 if (spec->unsol_event)
11001 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010011002}
11003
11004/*
11005 * configuration and preset
11006 */
11007static const char *alc269_models[ALC269_MODEL_LAST] = {
11008 [ALC269_BASIC] = "basic",
11009};
11010
11011static struct snd_pci_quirk alc269_cfg_tbl[] = {
11012 {}
11013};
11014
11015static struct alc_config_preset alc269_presets[] = {
11016 [ALC269_BASIC] = {
11017 .mixers = { alc269_base_mixer },
11018 .init_verbs = { alc269_init_verbs },
11019 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
11020 .dac_nids = alc269_dac_nids,
11021 .hp_nid = 0x03,
11022 .num_channel_mode = ARRAY_SIZE(alc269_modes),
11023 .channel_mode = alc269_modes,
11024 .input_mux = &alc269_capture_source,
11025 },
11026};
11027
11028static int patch_alc269(struct hda_codec *codec)
11029{
11030 struct alc_spec *spec;
11031 int board_config;
11032 int err;
11033
11034 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
11035 if (spec == NULL)
11036 return -ENOMEM;
11037
11038 codec->spec = spec;
11039
11040 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
11041 alc269_models,
11042 alc269_cfg_tbl);
11043
11044 if (board_config < 0) {
11045 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
11046 "trying auto-probe from BIOS...\n");
11047 board_config = ALC269_AUTO;
11048 }
11049
11050 if (board_config == ALC269_AUTO) {
11051 /* automatic parse from the BIOS config */
11052 err = alc269_parse_auto_config(codec);
11053 if (err < 0) {
11054 alc_free(codec);
11055 return err;
11056 } else if (!err) {
11057 printk(KERN_INFO
11058 "hda_codec: Cannot set up configuration "
11059 "from BIOS. Using base mode...\n");
11060 board_config = ALC269_BASIC;
11061 }
11062 }
11063
11064 if (board_config != ALC269_AUTO)
11065 setup_preset(spec, &alc269_presets[board_config]);
11066
11067 spec->stream_name_analog = "ALC269 Analog";
11068 spec->stream_analog_playback = &alc269_pcm_analog_playback;
11069 spec->stream_analog_capture = &alc269_pcm_analog_capture;
11070
11071 spec->stream_name_digital = "ALC269 Digital";
11072 spec->stream_digital_playback = &alc269_pcm_digital_playback;
11073 spec->stream_digital_capture = &alc269_pcm_digital_capture;
11074
11075 spec->adc_nids = alc269_adc_nids;
11076 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
11077 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
11078 spec->num_mixers++;
11079
11080 codec->patch_ops = alc_patch_ops;
11081 if (board_config == ALC269_AUTO)
11082 spec->init_hook = alc269_auto_init;
11083#ifdef CONFIG_SND_HDA_POWER_SAVE
11084 if (!spec->loopback.amplist)
11085 spec->loopback.amplist = alc269_loopbacks;
11086#endif
11087
11088 return 0;
11089}
11090
11091/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011092 * ALC861 channel source setting (2/6 channel selection for 3-stack)
11093 */
11094
11095/*
11096 * set the path ways for 2 channel output
11097 * need to set the codec line out and mic 1 pin widgets to inputs
11098 */
11099static struct hda_verb alc861_threestack_ch2_init[] = {
11100 /* set pin widget 1Ah (line in) for input */
11101 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011102 /* set pin widget 18h (mic1/2) for input, for mic also enable
11103 * the vref
11104 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011105 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11106
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011107 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
11108#if 0
11109 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
11110 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
11111#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011112 { } /* end */
11113};
11114/*
11115 * 6ch mode
11116 * need to set the codec line out and mic 1 pin widgets to outputs
11117 */
11118static struct hda_verb alc861_threestack_ch6_init[] = {
11119 /* set pin widget 1Ah (line in) for output (Back Surround)*/
11120 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11121 /* set pin widget 18h (mic1) for output (CLFE)*/
11122 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11123
11124 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011125 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011126
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011127 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
11128#if 0
11129 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
11130 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
11131#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011132 { } /* end */
11133};
11134
11135static struct hda_channel_mode alc861_threestack_modes[2] = {
11136 { 2, alc861_threestack_ch2_init },
11137 { 6, alc861_threestack_ch6_init },
11138};
Takashi Iwai22309c32006-08-09 16:57:28 +020011139/* Set mic1 as input and unmute the mixer */
11140static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
11141 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11142 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
11143 { } /* end */
11144};
11145/* Set mic1 as output and mute mixer */
11146static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
11147 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11148 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
11149 { } /* end */
11150};
11151
11152static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
11153 { 2, alc861_uniwill_m31_ch2_init },
11154 { 4, alc861_uniwill_m31_ch4_init },
11155};
Kailang Yangdf694da2005-12-05 19:42:22 +010011156
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011157/* Set mic1 and line-in as input and unmute the mixer */
11158static struct hda_verb alc861_asus_ch2_init[] = {
11159 /* set pin widget 1Ah (line in) for input */
11160 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011161 /* set pin widget 18h (mic1/2) for input, for mic also enable
11162 * the vref
11163 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011164 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11165
11166 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
11167#if 0
11168 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
11169 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
11170#endif
11171 { } /* end */
11172};
11173/* Set mic1 nad line-in as output and mute mixer */
11174static struct hda_verb alc861_asus_ch6_init[] = {
11175 /* set pin widget 1Ah (line in) for output (Back Surround)*/
11176 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11177 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
11178 /* set pin widget 18h (mic1) for output (CLFE)*/
11179 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11180 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
11181 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
11182 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
11183
11184 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
11185#if 0
11186 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
11187 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
11188#endif
11189 { } /* end */
11190};
11191
11192static struct hda_channel_mode alc861_asus_modes[2] = {
11193 { 2, alc861_asus_ch2_init },
11194 { 6, alc861_asus_ch6_init },
11195};
11196
Kailang Yangdf694da2005-12-05 19:42:22 +010011197/* patch-ALC861 */
11198
11199static struct snd_kcontrol_new alc861_base_mixer[] = {
11200 /* output mixer control */
11201 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11202 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11203 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11204 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11205 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
11206
11207 /*Input mixer control */
11208 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11209 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
11210 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11211 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11212 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11213 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11214 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11215 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11216 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
11217 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011218
Kailang Yangdf694da2005-12-05 19:42:22 +010011219 /* Capture mixer control */
11220 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11221 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11222 {
11223 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11224 .name = "Capture Source",
11225 .count = 1,
11226 .info = alc_mux_enum_info,
11227 .get = alc_mux_enum_get,
11228 .put = alc_mux_enum_put,
11229 },
11230 { } /* end */
11231};
11232
11233static struct snd_kcontrol_new alc861_3ST_mixer[] = {
11234 /* output mixer control */
11235 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11236 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11237 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11238 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11239 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
11240
11241 /* Input mixer control */
11242 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11243 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
11244 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11245 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11246 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11247 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11248 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11249 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11250 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
11251 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011252
Kailang Yangdf694da2005-12-05 19:42:22 +010011253 /* Capture mixer control */
11254 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11255 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11256 {
11257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11258 .name = "Capture Source",
11259 .count = 1,
11260 .info = alc_mux_enum_info,
11261 .get = alc_mux_enum_get,
11262 .put = alc_mux_enum_put,
11263 },
11264 {
11265 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11266 .name = "Channel Mode",
11267 .info = alc_ch_mode_info,
11268 .get = alc_ch_mode_get,
11269 .put = alc_ch_mode_put,
11270 .private_value = ARRAY_SIZE(alc861_threestack_modes),
11271 },
11272 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011273};
11274
Takashi Iwaid1d985f2006-11-23 19:27:12 +010011275static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011276 /* output mixer control */
11277 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11278 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11279 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11280
11281 /*Capture mixer control */
11282 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11283 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11284 {
11285 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11286 .name = "Capture Source",
11287 .count = 1,
11288 .info = alc_mux_enum_info,
11289 .get = alc_mux_enum_get,
11290 .put = alc_mux_enum_put,
11291 },
11292
11293 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011294};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011295
Takashi Iwai22309c32006-08-09 16:57:28 +020011296static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
11297 /* output mixer control */
11298 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11299 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11300 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11301 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11302 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
11303
11304 /* Input mixer control */
11305 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11306 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
11307 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11308 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11309 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11310 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11311 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11312 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11313 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
11314 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011315
Takashi Iwai22309c32006-08-09 16:57:28 +020011316 /* Capture mixer control */
11317 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11318 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11319 {
11320 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11321 .name = "Capture Source",
11322 .count = 1,
11323 .info = alc_mux_enum_info,
11324 .get = alc_mux_enum_get,
11325 .put = alc_mux_enum_put,
11326 },
11327 {
11328 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11329 .name = "Channel Mode",
11330 .info = alc_ch_mode_info,
11331 .get = alc_ch_mode_get,
11332 .put = alc_ch_mode_put,
11333 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
11334 },
11335 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011336};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011337
11338static struct snd_kcontrol_new alc861_asus_mixer[] = {
11339 /* output mixer control */
11340 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
11341 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
11342 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
11343 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
11344 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
11345
11346 /* Input mixer control */
11347 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
11348 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11349 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11350 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11351 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
11352 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
11353 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
11354 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
11355 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011356 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
11357
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011358 /* Capture mixer control */
11359 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11360 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11361 {
11362 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11363 .name = "Capture Source",
11364 .count = 1,
11365 .info = alc_mux_enum_info,
11366 .get = alc_mux_enum_get,
11367 .put = alc_mux_enum_put,
11368 },
11369 {
11370 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11371 .name = "Channel Mode",
11372 .info = alc_ch_mode_info,
11373 .get = alc_ch_mode_get,
11374 .put = alc_ch_mode_put,
11375 .private_value = ARRAY_SIZE(alc861_asus_modes),
11376 },
11377 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011378};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011379
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011380/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010011381static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011382 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
11383 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
11384 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
11385 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
11386 { }
11387};
11388
Kailang Yangdf694da2005-12-05 19:42:22 +010011389/*
11390 * generic initialization of ADC, input mixers and output mixers
11391 */
11392static struct hda_verb alc861_base_init_verbs[] = {
11393 /*
11394 * Unmute ADC0 and set the default input to mic-in
11395 */
11396 /* port-A for surround (rear panel) */
11397 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11398 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
11399 /* port-B for mic-in (rear panel) with vref */
11400 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11401 /* port-C for line-in (rear panel) */
11402 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11403 /* port-D for Front */
11404 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11405 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11406 /* port-E for HP out (front panel) */
11407 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11408 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011409 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011410 /* port-F for mic-in (front panel) with vref */
11411 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11412 /* port-G for CLFE (rear panel) */
11413 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11414 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
11415 /* port-H for side (rear panel) */
11416 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11417 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
11418 /* CD-in */
11419 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11420 /* route front mic to ADC1*/
11421 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11422 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11423
11424 /* Unmute DAC0~3 & spdif out*/
11425 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11426 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11427 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11428 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11429 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11430
11431 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11432 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11433 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11434 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11435 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11436
11437 /* Unmute Stereo Mixer 15 */
11438 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11439 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11440 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011441 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011442
11443 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11444 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11445 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11446 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11447 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11448 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11449 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11450 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011451 /* hp used DAC 3 (Front) */
11452 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011453 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11454
11455 { }
11456};
11457
11458static struct hda_verb alc861_threestack_init_verbs[] = {
11459 /*
11460 * Unmute ADC0 and set the default input to mic-in
11461 */
11462 /* port-A for surround (rear panel) */
11463 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11464 /* port-B for mic-in (rear panel) with vref */
11465 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11466 /* port-C for line-in (rear panel) */
11467 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11468 /* port-D for Front */
11469 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11470 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11471 /* port-E for HP out (front panel) */
11472 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11473 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011474 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011475 /* port-F for mic-in (front panel) with vref */
11476 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11477 /* port-G for CLFE (rear panel) */
11478 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11479 /* port-H for side (rear panel) */
11480 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11481 /* CD-in */
11482 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11483 /* route front mic to ADC1*/
11484 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11486 /* Unmute DAC0~3 & spdif out*/
11487 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11488 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11489 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11490 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11491 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11492
11493 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11494 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11495 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11496 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11497 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11498
11499 /* Unmute Stereo Mixer 15 */
11500 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11501 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11502 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011503 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011504
11505 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11506 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11507 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11508 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11509 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11510 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11511 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11512 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011513 /* hp used DAC 3 (Front) */
11514 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011515 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11516 { }
11517};
Takashi Iwai22309c32006-08-09 16:57:28 +020011518
11519static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
11520 /*
11521 * Unmute ADC0 and set the default input to mic-in
11522 */
11523 /* port-A for surround (rear panel) */
11524 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11525 /* port-B for mic-in (rear panel) with vref */
11526 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11527 /* port-C for line-in (rear panel) */
11528 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11529 /* port-D for Front */
11530 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11531 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11532 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011533 /* this has to be set to VREF80 */
11534 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011535 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011536 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011537 /* port-F for mic-in (front panel) with vref */
11538 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11539 /* port-G for CLFE (rear panel) */
11540 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11541 /* port-H for side (rear panel) */
11542 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11543 /* CD-in */
11544 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11545 /* route front mic to ADC1*/
11546 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11547 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11548 /* Unmute DAC0~3 & spdif out*/
11549 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11550 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11551 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11552 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11553 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11554
11555 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11556 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11557 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11558 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11559 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11560
11561 /* Unmute Stereo Mixer 15 */
11562 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11563 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11564 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011565 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020011566
11567 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11568 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11569 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11570 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11571 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11572 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11573 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11574 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011575 /* hp used DAC 3 (Front) */
11576 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020011577 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11578 { }
11579};
11580
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011581static struct hda_verb alc861_asus_init_verbs[] = {
11582 /*
11583 * Unmute ADC0 and set the default input to mic-in
11584 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011585 /* port-A for surround (rear panel)
11586 * according to codec#0 this is the HP jack
11587 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011588 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
11589 /* route front PCM to HP */
11590 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
11591 /* port-B for mic-in (rear panel) with vref */
11592 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11593 /* port-C for line-in (rear panel) */
11594 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11595 /* port-D for Front */
11596 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11597 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11598 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011599 /* this has to be set to VREF80 */
11600 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011601 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011602 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011603 /* port-F for mic-in (front panel) with vref */
11604 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11605 /* port-G for CLFE (rear panel) */
11606 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11607 /* port-H for side (rear panel) */
11608 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11609 /* CD-in */
11610 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11611 /* route front mic to ADC1*/
11612 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11613 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11614 /* Unmute DAC0~3 & spdif out*/
11615 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11616 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11617 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11618 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11619 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11620 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11621 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11622 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11623 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11624 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11625
11626 /* Unmute Stereo Mixer 15 */
11627 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11628 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11629 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011630 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011631
11632 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11633 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11634 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11635 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11636 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11637 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11638 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11639 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011640 /* hp used DAC 3 (Front) */
11641 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011642 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11643 { }
11644};
11645
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011646/* additional init verbs for ASUS laptops */
11647static struct hda_verb alc861_asus_laptop_init_verbs[] = {
11648 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
11649 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
11650 { }
11651};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011652
Kailang Yangdf694da2005-12-05 19:42:22 +010011653/*
11654 * generic initialization of ADC, input mixers and output mixers
11655 */
11656static struct hda_verb alc861_auto_init_verbs[] = {
11657 /*
11658 * Unmute ADC0 and set the default input to mic-in
11659 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011660 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010011661 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11662
11663 /* Unmute DAC0~3 & spdif out*/
11664 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11665 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11666 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11667 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11668 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11669
11670 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11671 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11672 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11673 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11674 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11675
11676 /* Unmute Stereo Mixer 15 */
11677 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11678 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11679 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11680 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
11681
11682 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11683 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11684 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11685 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11686 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11687 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11688 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11689 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11690
11691 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11692 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011693 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11694 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011695 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11696 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011697 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11698 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011699
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011700 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011701
11702 { }
11703};
11704
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011705static struct hda_verb alc861_toshiba_init_verbs[] = {
11706 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011707
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011708 { }
11709};
11710
11711/* toggle speaker-output according to the hp-jack state */
11712static void alc861_toshiba_automute(struct hda_codec *codec)
11713{
11714 unsigned int present;
11715
11716 present = snd_hda_codec_read(codec, 0x0f, 0,
11717 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011718 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
11719 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
11720 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
11721 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011722}
11723
11724static void alc861_toshiba_unsol_event(struct hda_codec *codec,
11725 unsigned int res)
11726{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011727 if ((res >> 26) == ALC880_HP_EVENT)
11728 alc861_toshiba_automute(codec);
11729}
11730
Kailang Yangdf694da2005-12-05 19:42:22 +010011731/* pcm configuration: identiacal with ALC880 */
11732#define alc861_pcm_analog_playback alc880_pcm_analog_playback
11733#define alc861_pcm_analog_capture alc880_pcm_analog_capture
11734#define alc861_pcm_digital_playback alc880_pcm_digital_playback
11735#define alc861_pcm_digital_capture alc880_pcm_digital_capture
11736
11737
11738#define ALC861_DIGOUT_NID 0x07
11739
11740static struct hda_channel_mode alc861_8ch_modes[1] = {
11741 { 8, NULL }
11742};
11743
11744static hda_nid_t alc861_dac_nids[4] = {
11745 /* front, surround, clfe, side */
11746 0x03, 0x06, 0x05, 0x04
11747};
11748
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011749static hda_nid_t alc660_dac_nids[3] = {
11750 /* front, clfe, surround */
11751 0x03, 0x05, 0x06
11752};
11753
Kailang Yangdf694da2005-12-05 19:42:22 +010011754static hda_nid_t alc861_adc_nids[1] = {
11755 /* ADC0-2 */
11756 0x08,
11757};
11758
11759static struct hda_input_mux alc861_capture_source = {
11760 .num_items = 5,
11761 .items = {
11762 { "Mic", 0x0 },
11763 { "Front Mic", 0x3 },
11764 { "Line", 0x1 },
11765 { "CD", 0x4 },
11766 { "Mixer", 0x5 },
11767 },
11768};
11769
11770/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011771static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
11772 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011773{
11774 int i;
11775 hda_nid_t nid;
11776
11777 spec->multiout.dac_nids = spec->private_dac_nids;
11778 for (i = 0; i < cfg->line_outs; i++) {
11779 nid = cfg->line_out_pins[i];
11780 if (nid) {
11781 if (i >= ARRAY_SIZE(alc861_dac_nids))
11782 continue;
11783 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
11784 }
11785 }
11786 spec->multiout.num_dacs = cfg->line_outs;
11787 return 0;
11788}
11789
11790/* add playback controls from the parsed DAC table */
11791static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
11792 const struct auto_pin_cfg *cfg)
11793{
11794 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011795 static const char *chname[4] = {
11796 "Front", "Surround", NULL /*CLFE*/, "Side"
11797 };
Kailang Yangdf694da2005-12-05 19:42:22 +010011798 hda_nid_t nid;
11799 int i, idx, err;
11800
11801 for (i = 0; i < cfg->line_outs; i++) {
11802 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011803 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010011804 continue;
11805 if (nid == 0x05) {
11806 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011807 err = add_control(spec, ALC_CTL_BIND_MUTE,
11808 "Center Playback Switch",
11809 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
11810 HDA_OUTPUT));
11811 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011812 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011813 err = add_control(spec, ALC_CTL_BIND_MUTE,
11814 "LFE Playback Switch",
11815 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11816 HDA_OUTPUT));
11817 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011818 return err;
11819 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011820 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
11821 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010011822 if (nid == alc861_dac_nids[idx])
11823 break;
11824 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011825 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
11826 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11827 HDA_OUTPUT));
11828 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011829 return err;
11830 }
11831 }
11832 return 0;
11833}
11834
11835static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
11836{
11837 int err;
11838 hda_nid_t nid;
11839
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011840 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010011841 return 0;
11842
11843 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
11844 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011845 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11846 "Headphone Playback Switch",
11847 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11848 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011849 return err;
11850 spec->multiout.hp_nid = nid;
11851 }
11852 return 0;
11853}
11854
11855/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011856static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
11857 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011858{
Kailang Yangdf694da2005-12-05 19:42:22 +010011859 struct hda_input_mux *imux = &spec->private_imux;
11860 int i, err, idx, idx1;
11861
11862 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011863 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011864 case 0x0c:
11865 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011866 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011867 break;
11868 case 0x0f:
11869 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011870 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011871 break;
11872 case 0x0d:
11873 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011874 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011875 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011876 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010011877 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011878 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011879 break;
11880 case 0x11:
11881 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011882 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010011883 break;
11884 default:
11885 continue;
11886 }
11887
Takashi Iwai4a471b72005-12-07 13:56:29 +010011888 err = new_analog_input(spec, cfg->input_pins[i],
11889 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010011890 if (err < 0)
11891 return err;
11892
Takashi Iwai4a471b72005-12-07 13:56:29 +010011893 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010011894 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011895 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010011896 }
11897 return 0;
11898}
11899
11900static struct snd_kcontrol_new alc861_capture_mixer[] = {
11901 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11902 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11903
11904 {
11905 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11906 /* The multiple "Capture Source" controls confuse alsamixer
11907 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010011908 */
11909 /* .name = "Capture Source", */
11910 .name = "Input Source",
11911 .count = 1,
11912 .info = alc_mux_enum_info,
11913 .get = alc_mux_enum_get,
11914 .put = alc_mux_enum_put,
11915 },
11916 { } /* end */
11917};
11918
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011919static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
11920 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010011921 int pin_type, int dac_idx)
11922{
Jacek Luczak564c5be2008-05-03 18:41:23 +020011923 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
11924 pin_type);
11925 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11926 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010011927}
11928
11929static void alc861_auto_init_multi_out(struct hda_codec *codec)
11930{
11931 struct alc_spec *spec = codec->spec;
11932 int i;
11933
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011934 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010011935 for (i = 0; i < spec->autocfg.line_outs; i++) {
11936 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011937 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011938 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011939 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011940 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011941 }
11942}
11943
11944static void alc861_auto_init_hp_out(struct hda_codec *codec)
11945{
11946 struct alc_spec *spec = codec->spec;
11947 hda_nid_t pin;
11948
Takashi Iwaieb06ed82006-09-20 17:10:27 +020011949 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011950 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011951 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
11952 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011953 pin = spec->autocfg.speaker_pins[0];
11954 if (pin)
11955 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010011956}
11957
11958static void alc861_auto_init_analog_input(struct hda_codec *codec)
11959{
11960 struct alc_spec *spec = codec->spec;
11961 int i;
11962
11963 for (i = 0; i < AUTO_PIN_LAST; i++) {
11964 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011965 if (nid >= 0x0c && nid <= 0x11) {
11966 snd_hda_codec_write(codec, nid, 0,
11967 AC_VERB_SET_PIN_WIDGET_CONTROL,
11968 i <= AUTO_PIN_FRONT_MIC ?
11969 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010011970 }
11971 }
11972}
11973
11974/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011975/* return 1 if successful, 0 if the proper config is not found,
11976 * or a negative error code
11977 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011978static int alc861_parse_auto_config(struct hda_codec *codec)
11979{
11980 struct alc_spec *spec = codec->spec;
11981 int err;
11982 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
11983
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011984 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11985 alc861_ignore);
11986 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011987 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011988 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010011989 return 0; /* can't find valid BIOS pin config */
11990
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011991 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
11992 if (err < 0)
11993 return err;
11994 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
11995 if (err < 0)
11996 return err;
11997 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
11998 if (err < 0)
11999 return err;
12000 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
12001 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012002 return err;
12003
12004 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12005
12006 if (spec->autocfg.dig_out_pin)
12007 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
12008
12009 if (spec->kctl_alloc)
12010 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12011
12012 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
12013
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012014 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010012015 spec->input_mux = &spec->private_imux;
12016
12017 spec->adc_nids = alc861_adc_nids;
12018 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
12019 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
12020 spec->num_mixers++;
12021
12022 return 1;
12023}
12024
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012025/* additional initialization for auto-configuration model */
12026static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012027{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012028 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012029 alc861_auto_init_multi_out(codec);
12030 alc861_auto_init_hp_out(codec);
12031 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012032 if (spec->unsol_event)
12033 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012034}
12035
Takashi Iwaicb53c622007-08-10 17:21:45 +020012036#ifdef CONFIG_SND_HDA_POWER_SAVE
12037static struct hda_amp_list alc861_loopbacks[] = {
12038 { 0x15, HDA_INPUT, 0 },
12039 { 0x15, HDA_INPUT, 1 },
12040 { 0x15, HDA_INPUT, 2 },
12041 { 0x15, HDA_INPUT, 3 },
12042 { } /* end */
12043};
12044#endif
12045
Kailang Yangdf694da2005-12-05 19:42:22 +010012046
12047/*
12048 * configuration and preset
12049 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012050static const char *alc861_models[ALC861_MODEL_LAST] = {
12051 [ALC861_3ST] = "3stack",
12052 [ALC660_3ST] = "3stack-660",
12053 [ALC861_3ST_DIG] = "3stack-dig",
12054 [ALC861_6ST_DIG] = "6stack-dig",
12055 [ALC861_UNIWILL_M31] = "uniwill-m31",
12056 [ALC861_TOSHIBA] = "toshiba",
12057 [ALC861_ASUS] = "asus",
12058 [ALC861_ASUS_LAPTOP] = "asus-laptop",
12059 [ALC861_AUTO] = "auto",
12060};
12061
12062static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010012063 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012064 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
12065 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
12066 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012067 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020012068 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010012069 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020012070 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
12071 * Any other models that need this preset?
12072 */
12073 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020012074 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
12075 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012076 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
12077 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
12078 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
12079 /* FIXME: the below seems conflict */
12080 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
12081 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
12082 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010012083 {}
12084};
12085
12086static struct alc_config_preset alc861_presets[] = {
12087 [ALC861_3ST] = {
12088 .mixers = { alc861_3ST_mixer },
12089 .init_verbs = { alc861_threestack_init_verbs },
12090 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12091 .dac_nids = alc861_dac_nids,
12092 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
12093 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020012094 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010012095 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12096 .adc_nids = alc861_adc_nids,
12097 .input_mux = &alc861_capture_source,
12098 },
12099 [ALC861_3ST_DIG] = {
12100 .mixers = { alc861_base_mixer },
12101 .init_verbs = { alc861_threestack_init_verbs },
12102 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12103 .dac_nids = alc861_dac_nids,
12104 .dig_out_nid = ALC861_DIGOUT_NID,
12105 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
12106 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020012107 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010012108 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12109 .adc_nids = alc861_adc_nids,
12110 .input_mux = &alc861_capture_source,
12111 },
12112 [ALC861_6ST_DIG] = {
12113 .mixers = { alc861_base_mixer },
12114 .init_verbs = { alc861_base_init_verbs },
12115 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12116 .dac_nids = alc861_dac_nids,
12117 .dig_out_nid = ALC861_DIGOUT_NID,
12118 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
12119 .channel_mode = alc861_8ch_modes,
12120 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12121 .adc_nids = alc861_adc_nids,
12122 .input_mux = &alc861_capture_source,
12123 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012124 [ALC660_3ST] = {
12125 .mixers = { alc861_3ST_mixer },
12126 .init_verbs = { alc861_threestack_init_verbs },
12127 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
12128 .dac_nids = alc660_dac_nids,
12129 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
12130 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020012131 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012132 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12133 .adc_nids = alc861_adc_nids,
12134 .input_mux = &alc861_capture_source,
12135 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012136 [ALC861_UNIWILL_M31] = {
12137 .mixers = { alc861_uniwill_m31_mixer },
12138 .init_verbs = { alc861_uniwill_m31_init_verbs },
12139 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12140 .dac_nids = alc861_dac_nids,
12141 .dig_out_nid = ALC861_DIGOUT_NID,
12142 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
12143 .channel_mode = alc861_uniwill_m31_modes,
12144 .need_dac_fix = 1,
12145 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12146 .adc_nids = alc861_adc_nids,
12147 .input_mux = &alc861_capture_source,
12148 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012149 [ALC861_TOSHIBA] = {
12150 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012151 .init_verbs = { alc861_base_init_verbs,
12152 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012153 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12154 .dac_nids = alc861_dac_nids,
12155 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
12156 .channel_mode = alc883_3ST_2ch_modes,
12157 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12158 .adc_nids = alc861_adc_nids,
12159 .input_mux = &alc861_capture_source,
12160 .unsol_event = alc861_toshiba_unsol_event,
12161 .init_hook = alc861_toshiba_automute,
12162 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012163 [ALC861_ASUS] = {
12164 .mixers = { alc861_asus_mixer },
12165 .init_verbs = { alc861_asus_init_verbs },
12166 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12167 .dac_nids = alc861_dac_nids,
12168 .dig_out_nid = ALC861_DIGOUT_NID,
12169 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
12170 .channel_mode = alc861_asus_modes,
12171 .need_dac_fix = 1,
12172 .hp_nid = 0x06,
12173 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12174 .adc_nids = alc861_adc_nids,
12175 .input_mux = &alc861_capture_source,
12176 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012177 [ALC861_ASUS_LAPTOP] = {
12178 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
12179 .init_verbs = { alc861_asus_init_verbs,
12180 alc861_asus_laptop_init_verbs },
12181 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
12182 .dac_nids = alc861_dac_nids,
12183 .dig_out_nid = ALC861_DIGOUT_NID,
12184 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
12185 .channel_mode = alc883_3ST_2ch_modes,
12186 .need_dac_fix = 1,
12187 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
12188 .adc_nids = alc861_adc_nids,
12189 .input_mux = &alc861_capture_source,
12190 },
12191};
Kailang Yangdf694da2005-12-05 19:42:22 +010012192
12193
12194static int patch_alc861(struct hda_codec *codec)
12195{
12196 struct alc_spec *spec;
12197 int board_config;
12198 int err;
12199
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012200 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012201 if (spec == NULL)
12202 return -ENOMEM;
12203
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012204 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012205
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012206 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
12207 alc861_models,
12208 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012209
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012210 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012211 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
12212 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012213 board_config = ALC861_AUTO;
12214 }
12215
12216 if (board_config == ALC861_AUTO) {
12217 /* automatic parse from the BIOS config */
12218 err = alc861_parse_auto_config(codec);
12219 if (err < 0) {
12220 alc_free(codec);
12221 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012222 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012223 printk(KERN_INFO
12224 "hda_codec: Cannot set up configuration "
12225 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012226 board_config = ALC861_3ST_DIG;
12227 }
12228 }
12229
12230 if (board_config != ALC861_AUTO)
12231 setup_preset(spec, &alc861_presets[board_config]);
12232
12233 spec->stream_name_analog = "ALC861 Analog";
12234 spec->stream_analog_playback = &alc861_pcm_analog_playback;
12235 spec->stream_analog_capture = &alc861_pcm_analog_capture;
12236
12237 spec->stream_name_digital = "ALC861 Digital";
12238 spec->stream_digital_playback = &alc861_pcm_digital_playback;
12239 spec->stream_digital_capture = &alc861_pcm_digital_capture;
12240
Takashi Iwai2134ea42008-01-10 16:53:55 +010012241 spec->vmaster_nid = 0x03;
12242
Kailang Yangdf694da2005-12-05 19:42:22 +010012243 codec->patch_ops = alc_patch_ops;
12244 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012245 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012246#ifdef CONFIG_SND_HDA_POWER_SAVE
12247 if (!spec->loopback.amplist)
12248 spec->loopback.amplist = alc861_loopbacks;
12249#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012250
12251 return 0;
12252}
12253
12254/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012255 * ALC861-VD support
12256 *
12257 * Based on ALC882
12258 *
12259 * In addition, an independent DAC
12260 */
12261#define ALC861VD_DIGOUT_NID 0x06
12262
12263static hda_nid_t alc861vd_dac_nids[4] = {
12264 /* front, surr, clfe, side surr */
12265 0x02, 0x03, 0x04, 0x05
12266};
12267
12268/* dac_nids for ALC660vd are in a different order - according to
12269 * Realtek's driver.
12270 * This should probably tesult in a different mixer for 6stack models
12271 * of ALC660vd codecs, but for now there is only 3stack mixer
12272 * - and it is the same as in 861vd.
12273 * adc_nids in ALC660vd are (is) the same as in 861vd
12274 */
12275static hda_nid_t alc660vd_dac_nids[3] = {
12276 /* front, rear, clfe, rear_surr */
12277 0x02, 0x04, 0x03
12278};
12279
12280static hda_nid_t alc861vd_adc_nids[1] = {
12281 /* ADC0 */
12282 0x09,
12283};
12284
Takashi Iwaie1406342008-02-11 18:32:32 +010012285static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
12286
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012287/* input MUX */
12288/* FIXME: should be a matrix-type input source selection */
12289static struct hda_input_mux alc861vd_capture_source = {
12290 .num_items = 4,
12291 .items = {
12292 { "Mic", 0x0 },
12293 { "Front Mic", 0x1 },
12294 { "Line", 0x2 },
12295 { "CD", 0x4 },
12296 },
12297};
12298
Kailang Yang272a5272007-05-14 11:00:38 +020012299static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010012300 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020012301 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010012302 { "Ext Mic", 0x0 },
12303 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020012304 },
12305};
12306
Kailang Yangd1a991a2007-08-15 16:21:59 +020012307static struct hda_input_mux alc861vd_hp_capture_source = {
12308 .num_items = 2,
12309 .items = {
12310 { "Front Mic", 0x0 },
12311 { "ATAPI Mic", 0x1 },
12312 },
12313};
12314
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012315#define alc861vd_mux_enum_info alc_mux_enum_info
12316#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010012317/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
12318#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012319
12320/*
12321 * 2ch mode
12322 */
12323static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
12324 { 2, NULL }
12325};
12326
12327/*
12328 * 6ch mode
12329 */
12330static struct hda_verb alc861vd_6stack_ch6_init[] = {
12331 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12332 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12333 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12334 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12335 { } /* end */
12336};
12337
12338/*
12339 * 8ch mode
12340 */
12341static struct hda_verb alc861vd_6stack_ch8_init[] = {
12342 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12343 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12344 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12345 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12346 { } /* end */
12347};
12348
12349static struct hda_channel_mode alc861vd_6stack_modes[2] = {
12350 { 6, alc861vd_6stack_ch6_init },
12351 { 8, alc861vd_6stack_ch8_init },
12352};
12353
12354static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
12355 {
12356 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12357 .name = "Channel Mode",
12358 .info = alc_ch_mode_info,
12359 .get = alc_ch_mode_get,
12360 .put = alc_ch_mode_put,
12361 },
12362 { } /* end */
12363};
12364
12365static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
12366 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
12367 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
12368
12369 {
12370 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12371 /* The multiple "Capture Source" controls confuse alsamixer
12372 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012373 */
12374 /* .name = "Capture Source", */
12375 .name = "Input Source",
12376 .count = 1,
12377 .info = alc861vd_mux_enum_info,
12378 .get = alc861vd_mux_enum_get,
12379 .put = alc861vd_mux_enum_put,
12380 },
12381 { } /* end */
12382};
12383
12384/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12385 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12386 */
12387static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
12388 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12389 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12390
12391 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12392 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
12393
12394 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
12395 HDA_OUTPUT),
12396 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
12397 HDA_OUTPUT),
12398 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
12399 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
12400
12401 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
12402 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
12403
12404 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12405
12406 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12407 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12408 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12409
12410 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12411 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12412 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12413
12414 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12415 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12416
12417 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12418 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12419
12420 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12421 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
12422
12423 { } /* end */
12424};
12425
12426static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
12427 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12428 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12429
12430 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12431
12432 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12433 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12434 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12435
12436 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12437 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12438 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12439
12440 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12441 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12442
12443 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12444 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12445
12446 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12447 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
12448
12449 { } /* end */
12450};
12451
Kailang Yangbdd148a2007-05-08 15:19:08 +020012452static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
12453 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12454 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
12455 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12456
12457 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12458
12459 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12460 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12461 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12462
12463 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12464 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12465 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12466
12467 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12468 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12469
12470 { } /* end */
12471};
12472
Tobin Davisb419f342008-03-07 11:57:51 +010012473/* Pin assignment: Speaker=0x14, HP = 0x15,
12474 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020012475 */
12476static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010012477 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12478 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012479 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12480 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010012481 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12482 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12483 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12484 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12485 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12486 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12487 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
12488 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012489 { } /* end */
12490};
12491
Kailang Yangd1a991a2007-08-15 16:21:59 +020012492/* Pin assignment: Speaker=0x14, Line-out = 0x15,
12493 * Front Mic=0x18, ATAPI Mic = 0x19,
12494 */
12495static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
12496 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12497 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12498 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12499 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12500 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12501 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12502 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12503 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12504
12505 { } /* end */
12506};
12507
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012508/*
12509 * generic initialization of ADC, input mixers and output mixers
12510 */
12511static struct hda_verb alc861vd_volume_init_verbs[] = {
12512 /*
12513 * Unmute ADC0 and set the default input to mic-in
12514 */
12515 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12516 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12517
12518 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
12519 * the analog-loopback mixer widget
12520 */
12521 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012522 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12523 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12524 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12525 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12526 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012527
12528 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020012529 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12530 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012533
12534 /*
12535 * Set up output mixers (0x02 - 0x05)
12536 */
12537 /* set vol=0 to output mixers */
12538 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12539 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12540 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12541 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12542
12543 /* set up input amps for analog loopback */
12544 /* Amp Indices: DAC = 0, mixer = 1 */
12545 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12546 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12547 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12548 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12549 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12550 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12551 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12552 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12553
12554 { }
12555};
12556
12557/*
12558 * 3-stack pin configuration:
12559 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
12560 */
12561static struct hda_verb alc861vd_3stack_init_verbs[] = {
12562 /*
12563 * Set pin mode and muting
12564 */
12565 /* set front pin widgets 0x14 for output */
12566 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12567 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12568 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12569
12570 /* Mic (rear) pin: input vref at 80% */
12571 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12572 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12573 /* Front Mic pin: input vref at 80% */
12574 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12575 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12576 /* Line In pin: input */
12577 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12578 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12579 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12580 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12581 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12582 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12583 /* CD pin widget for input */
12584 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12585
12586 { }
12587};
12588
12589/*
12590 * 6-stack pin configuration:
12591 */
12592static struct hda_verb alc861vd_6stack_init_verbs[] = {
12593 /*
12594 * Set pin mode and muting
12595 */
12596 /* set front pin widgets 0x14 for output */
12597 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12598 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12599 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12600
12601 /* Rear Pin: output 1 (0x0d) */
12602 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12603 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12604 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12605 /* CLFE Pin: output 2 (0x0e) */
12606 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12607 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12608 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
12609 /* Side Pin: output 3 (0x0f) */
12610 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12611 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12612 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
12613
12614 /* Mic (rear) pin: input vref at 80% */
12615 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12616 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12617 /* Front Mic pin: input vref at 80% */
12618 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12619 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12620 /* Line In pin: input */
12621 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12622 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12623 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12624 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12625 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12626 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12627 /* CD pin widget for input */
12628 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12629
12630 { }
12631};
12632
Kailang Yangbdd148a2007-05-08 15:19:08 +020012633static struct hda_verb alc861vd_eapd_verbs[] = {
12634 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12635 { }
12636};
12637
12638static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
12639 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12640 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12641 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12642 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12643 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12644 {}
12645};
12646
12647/* toggle speaker-output according to the hp-jack state */
12648static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
12649{
12650 unsigned int present;
12651 unsigned char bits;
12652
12653 present = snd_hda_codec_read(codec, 0x1b, 0,
12654 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012655 bits = present ? HDA_AMP_MUTE : 0;
12656 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12657 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012658}
12659
12660static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
12661{
12662 unsigned int present;
12663 unsigned char bits;
12664
12665 present = snd_hda_codec_read(codec, 0x18, 0,
12666 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012667 bits = present ? HDA_AMP_MUTE : 0;
12668 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
12669 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012670}
12671
12672static void alc861vd_lenovo_automute(struct hda_codec *codec)
12673{
12674 alc861vd_lenovo_hp_automute(codec);
12675 alc861vd_lenovo_mic_automute(codec);
12676}
12677
12678static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
12679 unsigned int res)
12680{
12681 switch (res >> 26) {
12682 case ALC880_HP_EVENT:
12683 alc861vd_lenovo_hp_automute(codec);
12684 break;
12685 case ALC880_MIC_EVENT:
12686 alc861vd_lenovo_mic_automute(codec);
12687 break;
12688 }
12689}
12690
Kailang Yang272a5272007-05-14 11:00:38 +020012691static struct hda_verb alc861vd_dallas_verbs[] = {
12692 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12693 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12694 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12695 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12696
12697 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12698 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12699 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12700 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12701 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12702 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12703 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12704 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12705
12706 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12707 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12708 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12709 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12710 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12711 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12712 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12713 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12714
12715 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12716 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12717 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12718 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12719 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12720 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12721 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12722 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12723
12724 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12725 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12726 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12727 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12728
12729 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12730 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12731 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12732
12733 { } /* end */
12734};
12735
12736/* toggle speaker-output according to the hp-jack state */
12737static void alc861vd_dallas_automute(struct hda_codec *codec)
12738{
12739 unsigned int present;
12740
12741 present = snd_hda_codec_read(codec, 0x15, 0,
12742 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012743 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12744 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020012745}
12746
12747static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
12748{
12749 if ((res >> 26) == ALC880_HP_EVENT)
12750 alc861vd_dallas_automute(codec);
12751}
12752
Takashi Iwaicb53c622007-08-10 17:21:45 +020012753#ifdef CONFIG_SND_HDA_POWER_SAVE
12754#define alc861vd_loopbacks alc880_loopbacks
12755#endif
12756
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012757/* pcm configuration: identiacal with ALC880 */
12758#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
12759#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
12760#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
12761#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
12762
12763/*
12764 * configuration and preset
12765 */
12766static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
12767 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012768 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012769 [ALC861VD_3ST] = "3stack",
12770 [ALC861VD_3ST_DIG] = "3stack-digout",
12771 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020012772 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020012773 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012774 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012775 [ALC861VD_AUTO] = "auto",
12776};
12777
12778static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012779 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
12780 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010012781 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012782 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020012783 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012784 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012785 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020012786 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020012787 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020012788 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010012789 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020012790 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012791 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
12792 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020012793 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012794 {}
12795};
12796
12797static struct alc_config_preset alc861vd_presets[] = {
12798 [ALC660VD_3ST] = {
12799 .mixers = { alc861vd_3st_mixer },
12800 .init_verbs = { alc861vd_volume_init_verbs,
12801 alc861vd_3stack_init_verbs },
12802 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12803 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012804 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12805 .channel_mode = alc861vd_3stack_2ch_modes,
12806 .input_mux = &alc861vd_capture_source,
12807 },
Mike Crash6963f842007-06-25 12:12:51 +020012808 [ALC660VD_3ST_DIG] = {
12809 .mixers = { alc861vd_3st_mixer },
12810 .init_verbs = { alc861vd_volume_init_verbs,
12811 alc861vd_3stack_init_verbs },
12812 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12813 .dac_nids = alc660vd_dac_nids,
12814 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020012815 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12816 .channel_mode = alc861vd_3stack_2ch_modes,
12817 .input_mux = &alc861vd_capture_source,
12818 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012819 [ALC861VD_3ST] = {
12820 .mixers = { alc861vd_3st_mixer },
12821 .init_verbs = { alc861vd_volume_init_verbs,
12822 alc861vd_3stack_init_verbs },
12823 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12824 .dac_nids = alc861vd_dac_nids,
12825 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12826 .channel_mode = alc861vd_3stack_2ch_modes,
12827 .input_mux = &alc861vd_capture_source,
12828 },
12829 [ALC861VD_3ST_DIG] = {
12830 .mixers = { alc861vd_3st_mixer },
12831 .init_verbs = { alc861vd_volume_init_verbs,
12832 alc861vd_3stack_init_verbs },
12833 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12834 .dac_nids = alc861vd_dac_nids,
12835 .dig_out_nid = ALC861VD_DIGOUT_NID,
12836 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12837 .channel_mode = alc861vd_3stack_2ch_modes,
12838 .input_mux = &alc861vd_capture_source,
12839 },
12840 [ALC861VD_6ST_DIG] = {
12841 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
12842 .init_verbs = { alc861vd_volume_init_verbs,
12843 alc861vd_6stack_init_verbs },
12844 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12845 .dac_nids = alc861vd_dac_nids,
12846 .dig_out_nid = ALC861VD_DIGOUT_NID,
12847 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
12848 .channel_mode = alc861vd_6stack_modes,
12849 .input_mux = &alc861vd_capture_source,
12850 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020012851 [ALC861VD_LENOVO] = {
12852 .mixers = { alc861vd_lenovo_mixer },
12853 .init_verbs = { alc861vd_volume_init_verbs,
12854 alc861vd_3stack_init_verbs,
12855 alc861vd_eapd_verbs,
12856 alc861vd_lenovo_unsol_verbs },
12857 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12858 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012859 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12860 .channel_mode = alc861vd_3stack_2ch_modes,
12861 .input_mux = &alc861vd_capture_source,
12862 .unsol_event = alc861vd_lenovo_unsol_event,
12863 .init_hook = alc861vd_lenovo_automute,
12864 },
Kailang Yang272a5272007-05-14 11:00:38 +020012865 [ALC861VD_DALLAS] = {
12866 .mixers = { alc861vd_dallas_mixer },
12867 .init_verbs = { alc861vd_dallas_verbs },
12868 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12869 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020012870 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12871 .channel_mode = alc861vd_3stack_2ch_modes,
12872 .input_mux = &alc861vd_dallas_capture_source,
12873 .unsol_event = alc861vd_dallas_unsol_event,
12874 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012875 },
12876 [ALC861VD_HP] = {
12877 .mixers = { alc861vd_hp_mixer },
12878 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
12879 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12880 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012881 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012882 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12883 .channel_mode = alc861vd_3stack_2ch_modes,
12884 .input_mux = &alc861vd_hp_capture_source,
12885 .unsol_event = alc861vd_dallas_unsol_event,
12886 .init_hook = alc861vd_dallas_automute,
12887 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012888};
12889
12890/*
12891 * BIOS auto configuration
12892 */
12893static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
12894 hda_nid_t nid, int pin_type, int dac_idx)
12895{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012896 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012897}
12898
12899static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
12900{
12901 struct alc_spec *spec = codec->spec;
12902 int i;
12903
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012904 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012905 for (i = 0; i <= HDA_SIDE; i++) {
12906 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012907 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012908 if (nid)
12909 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012910 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012911 }
12912}
12913
12914
12915static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
12916{
12917 struct alc_spec *spec = codec->spec;
12918 hda_nid_t pin;
12919
12920 pin = spec->autocfg.hp_pins[0];
12921 if (pin) /* connect to front and use dac 0 */
12922 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012923 pin = spec->autocfg.speaker_pins[0];
12924 if (pin)
12925 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012926}
12927
12928#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
12929#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
12930
12931static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
12932{
12933 struct alc_spec *spec = codec->spec;
12934 int i;
12935
12936 for (i = 0; i < AUTO_PIN_LAST; i++) {
12937 hda_nid_t nid = spec->autocfg.input_pins[i];
12938 if (alc861vd_is_input_pin(nid)) {
12939 snd_hda_codec_write(codec, nid, 0,
12940 AC_VERB_SET_PIN_WIDGET_CONTROL,
12941 i <= AUTO_PIN_FRONT_MIC ?
12942 PIN_VREF80 : PIN_IN);
12943 if (nid != ALC861VD_PIN_CD_NID)
12944 snd_hda_codec_write(codec, nid, 0,
12945 AC_VERB_SET_AMP_GAIN_MUTE,
12946 AMP_OUT_MUTE);
12947 }
12948 }
12949}
12950
12951#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
12952#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
12953
12954/* add playback controls from the parsed DAC table */
12955/* Based on ALC880 version. But ALC861VD has separate,
12956 * different NIDs for mute/unmute switch and volume control */
12957static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
12958 const struct auto_pin_cfg *cfg)
12959{
12960 char name[32];
12961 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
12962 hda_nid_t nid_v, nid_s;
12963 int i, err;
12964
12965 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012966 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012967 continue;
12968 nid_v = alc861vd_idx_to_mixer_vol(
12969 alc880_dac_to_idx(
12970 spec->multiout.dac_nids[i]));
12971 nid_s = alc861vd_idx_to_mixer_switch(
12972 alc880_dac_to_idx(
12973 spec->multiout.dac_nids[i]));
12974
12975 if (i == 2) {
12976 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012977 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12978 "Center Playback Volume",
12979 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
12980 HDA_OUTPUT));
12981 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012982 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012983 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12984 "LFE Playback Volume",
12985 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
12986 HDA_OUTPUT));
12987 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012988 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012989 err = add_control(spec, ALC_CTL_BIND_MUTE,
12990 "Center Playback Switch",
12991 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12992 HDA_INPUT));
12993 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012994 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012995 err = add_control(spec, ALC_CTL_BIND_MUTE,
12996 "LFE Playback Switch",
12997 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12998 HDA_INPUT));
12999 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013000 return err;
13001 } else {
13002 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013003 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13004 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
13005 HDA_OUTPUT));
13006 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013007 return err;
13008 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013009 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020013010 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013011 HDA_INPUT));
13012 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013013 return err;
13014 }
13015 }
13016 return 0;
13017}
13018
13019/* add playback controls for speaker and HP outputs */
13020/* Based on ALC880 version. But ALC861VD has separate,
13021 * different NIDs for mute/unmute switch and volume control */
13022static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
13023 hda_nid_t pin, const char *pfx)
13024{
13025 hda_nid_t nid_v, nid_s;
13026 int err;
13027 char name[32];
13028
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013029 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013030 return 0;
13031
13032 if (alc880_is_fixed_pin(pin)) {
13033 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13034 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013035 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013036 spec->multiout.hp_nid = nid_v;
13037 else
13038 spec->multiout.extra_out_nid[0] = nid_v;
13039 /* control HP volume/switch on the output mixer amp */
13040 nid_v = alc861vd_idx_to_mixer_vol(
13041 alc880_fixed_pin_idx(pin));
13042 nid_s = alc861vd_idx_to_mixer_switch(
13043 alc880_fixed_pin_idx(pin));
13044
13045 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013046 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13047 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
13048 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013049 return err;
13050 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013051 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13052 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
13053 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013054 return err;
13055 } else if (alc880_is_multi_pin(pin)) {
13056 /* set manual connection */
13057 /* we have only a switch on HP-out PIN */
13058 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013059 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
13060 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
13061 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013062 return err;
13063 }
13064 return 0;
13065}
13066
13067/* parse the BIOS configuration and set up the alc_spec
13068 * return 1 if successful, 0 if the proper config is not found,
13069 * or a negative error code
13070 * Based on ALC880 version - had to change it to override
13071 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
13072static int alc861vd_parse_auto_config(struct hda_codec *codec)
13073{
13074 struct alc_spec *spec = codec->spec;
13075 int err;
13076 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
13077
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013078 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13079 alc861vd_ignore);
13080 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013081 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013082 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013083 return 0; /* can't find valid BIOS pin config */
13084
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013085 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
13086 if (err < 0)
13087 return err;
13088 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
13089 if (err < 0)
13090 return err;
13091 err = alc861vd_auto_create_extra_out(spec,
13092 spec->autocfg.speaker_pins[0],
13093 "Speaker");
13094 if (err < 0)
13095 return err;
13096 err = alc861vd_auto_create_extra_out(spec,
13097 spec->autocfg.hp_pins[0],
13098 "Headphone");
13099 if (err < 0)
13100 return err;
13101 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
13102 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013103 return err;
13104
13105 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13106
13107 if (spec->autocfg.dig_out_pin)
13108 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
13109
13110 if (spec->kctl_alloc)
13111 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13112
13113 spec->init_verbs[spec->num_init_verbs++]
13114 = alc861vd_volume_init_verbs;
13115
13116 spec->num_mux_defs = 1;
13117 spec->input_mux = &spec->private_imux;
13118
Takashi Iwai776e1842007-08-29 15:07:11 +020013119 err = alc_auto_add_mic_boost(codec);
13120 if (err < 0)
13121 return err;
13122
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013123 return 1;
13124}
13125
13126/* additional initialization for auto-configuration model */
13127static void alc861vd_auto_init(struct hda_codec *codec)
13128{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013129 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013130 alc861vd_auto_init_multi_out(codec);
13131 alc861vd_auto_init_hp_out(codec);
13132 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013133 if (spec->unsol_event)
13134 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013135}
13136
13137static int patch_alc861vd(struct hda_codec *codec)
13138{
13139 struct alc_spec *spec;
13140 int err, board_config;
13141
13142 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13143 if (spec == NULL)
13144 return -ENOMEM;
13145
13146 codec->spec = spec;
13147
13148 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
13149 alc861vd_models,
13150 alc861vd_cfg_tbl);
13151
13152 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
13153 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
13154 "ALC861VD, trying auto-probe from BIOS...\n");
13155 board_config = ALC861VD_AUTO;
13156 }
13157
13158 if (board_config == ALC861VD_AUTO) {
13159 /* automatic parse from the BIOS config */
13160 err = alc861vd_parse_auto_config(codec);
13161 if (err < 0) {
13162 alc_free(codec);
13163 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013164 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013165 printk(KERN_INFO
13166 "hda_codec: Cannot set up configuration "
13167 "from BIOS. Using base mode...\n");
13168 board_config = ALC861VD_3ST;
13169 }
13170 }
13171
13172 if (board_config != ALC861VD_AUTO)
13173 setup_preset(spec, &alc861vd_presets[board_config]);
13174
13175 spec->stream_name_analog = "ALC861VD Analog";
13176 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
13177 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
13178
13179 spec->stream_name_digital = "ALC861VD Digital";
13180 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
13181 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
13182
13183 spec->adc_nids = alc861vd_adc_nids;
13184 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010013185 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013186
13187 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
13188 spec->num_mixers++;
13189
Takashi Iwai2134ea42008-01-10 16:53:55 +010013190 spec->vmaster_nid = 0x02;
13191
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013192 codec->patch_ops = alc_patch_ops;
13193
13194 if (board_config == ALC861VD_AUTO)
13195 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013196#ifdef CONFIG_SND_HDA_POWER_SAVE
13197 if (!spec->loopback.amplist)
13198 spec->loopback.amplist = alc861vd_loopbacks;
13199#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013200
13201 return 0;
13202}
13203
13204/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013205 * ALC662 support
13206 *
13207 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
13208 * configuration. Each pin widget can choose any input DACs and a mixer.
13209 * Each ADC is connected from a mixer of all inputs. This makes possible
13210 * 6-channel independent captures.
13211 *
13212 * In addition, an independent DAC for the multi-playback (not used in this
13213 * driver yet).
13214 */
13215#define ALC662_DIGOUT_NID 0x06
13216#define ALC662_DIGIN_NID 0x0a
13217
13218static hda_nid_t alc662_dac_nids[4] = {
13219 /* front, rear, clfe, rear_surr */
13220 0x02, 0x03, 0x04
13221};
13222
13223static hda_nid_t alc662_adc_nids[1] = {
13224 /* ADC1-2 */
13225 0x09,
13226};
Takashi Iwaie1406342008-02-11 18:32:32 +010013227
Kailang Yang77a261b2008-02-19 11:38:05 +010013228static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010013229
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013230/* input MUX */
13231/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013232static struct hda_input_mux alc662_capture_source = {
13233 .num_items = 4,
13234 .items = {
13235 { "Mic", 0x0 },
13236 { "Front Mic", 0x1 },
13237 { "Line", 0x2 },
13238 { "CD", 0x4 },
13239 },
13240};
13241
13242static struct hda_input_mux alc662_lenovo_101e_capture_source = {
13243 .num_items = 2,
13244 .items = {
13245 { "Mic", 0x1 },
13246 { "Line", 0x2 },
13247 },
13248};
Kailang Yang291702f2007-10-16 14:28:03 +020013249
13250static struct hda_input_mux alc662_eeepc_capture_source = {
13251 .num_items = 2,
13252 .items = {
13253 { "i-Mic", 0x1 },
13254 { "e-Mic", 0x0 },
13255 },
13256};
13257
Kailang Yang6dda9f42008-05-27 12:05:31 +020013258static struct hda_input_mux alc663_capture_source = {
13259 .num_items = 3,
13260 .items = {
13261 { "Mic", 0x0 },
13262 { "Front Mic", 0x1 },
13263 { "Line", 0x2 },
13264 },
13265};
13266
13267static struct hda_input_mux alc663_m51va_capture_source = {
13268 .num_items = 2,
13269 .items = {
13270 { "Ext-Mic", 0x0 },
13271 { "D-Mic", 0x9 },
13272 },
13273};
13274
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013275#define alc662_mux_enum_info alc_mux_enum_info
13276#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010013277#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013278
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013279/*
13280 * 2ch mode
13281 */
13282static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
13283 { 2, NULL }
13284};
13285
13286/*
13287 * 2ch mode
13288 */
13289static struct hda_verb alc662_3ST_ch2_init[] = {
13290 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
13291 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
13292 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
13293 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
13294 { } /* end */
13295};
13296
13297/*
13298 * 6ch mode
13299 */
13300static struct hda_verb alc662_3ST_ch6_init[] = {
13301 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13302 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
13303 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
13304 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13305 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
13306 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
13307 { } /* end */
13308};
13309
13310static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
13311 { 2, alc662_3ST_ch2_init },
13312 { 6, alc662_3ST_ch6_init },
13313};
13314
13315/*
13316 * 2ch mode
13317 */
13318static struct hda_verb alc662_sixstack_ch6_init[] = {
13319 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13320 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13321 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13322 { } /* end */
13323};
13324
13325/*
13326 * 6ch mode
13327 */
13328static struct hda_verb alc662_sixstack_ch8_init[] = {
13329 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13330 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13331 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13332 { } /* end */
13333};
13334
13335static struct hda_channel_mode alc662_5stack_modes[2] = {
13336 { 2, alc662_sixstack_ch6_init },
13337 { 6, alc662_sixstack_ch8_init },
13338};
13339
13340/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13341 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13342 */
13343
13344static struct snd_kcontrol_new alc662_base_mixer[] = {
13345 /* output mixer control */
13346 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013347 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013348 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013349 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013350 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13351 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013352 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
13353 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013354 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13355
13356 /*Input mixer control */
13357 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
13358 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
13359 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
13360 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
13361 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
13362 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
13363 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
13364 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013365 { } /* end */
13366};
13367
13368static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
13369 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013370 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013371 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13372 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13373 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13374 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13375 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13376 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13377 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13378 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13379 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13380 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13381 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013382 { } /* end */
13383};
13384
13385static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
13386 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013387 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013388 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013389 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013390 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13391 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010013392 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
13393 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013394 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13395 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13396 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13397 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13398 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13399 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13400 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13401 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13402 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13403 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13404 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013405 { } /* end */
13406};
13407
13408static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
13409 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13410 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010013411 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13412 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013413 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13414 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13415 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13416 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13417 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013418 { } /* end */
13419};
13420
Kailang Yang291702f2007-10-16 14:28:03 +020013421static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010013422 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020013423
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010013424 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13425 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020013426
13427 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
13428 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13429 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13430
13431 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
13432 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13433 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13434 { } /* end */
13435};
13436
Kailang Yang8c427222008-01-10 13:03:59 +010013437static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010013438 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13439 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010013440 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13441 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
13442 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
13443 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
13444 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
13445 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010013446 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010013447 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
13448 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13449 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13450 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13451 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13452 { } /* end */
13453};
13454
Kailang Yang6dda9f42008-05-27 12:05:31 +020013455static struct snd_kcontrol_new alc663_m51va_mixer[] = {
13456 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13457 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13458 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13459 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13460 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13461 HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
13462 { } /* end */
13463};
13464
13465static struct snd_kcontrol_new alc663_g71v_mixer[] = {
13466 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13467 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13468 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13469 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13470 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13471
13472 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13473 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13474 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13475 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13476 { } /* end */
13477};
13478
13479static struct snd_kcontrol_new alc663_g50v_mixer[] = {
13480 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13481 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13482 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13483
13484 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13486 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13487 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13488 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13489 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13490 { } /* end */
13491};
13492
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013493static struct snd_kcontrol_new alc662_chmode_mixer[] = {
13494 {
13495 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13496 .name = "Channel Mode",
13497 .info = alc_ch_mode_info,
13498 .get = alc_ch_mode_get,
13499 .put = alc_ch_mode_put,
13500 },
13501 { } /* end */
13502};
13503
13504static struct hda_verb alc662_init_verbs[] = {
13505 /* ADC: mute amp left and right */
13506 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13507 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13508 /* Front mixer: unmute input/output amp left and right (volume = 0) */
13509
Takashi Iwaicb53c622007-08-10 17:21:45 +020013510 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13511 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13512 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13513 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13514 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013515
Kailang Yangb60dd392007-09-20 12:50:29 +020013516 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13517 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13518 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13519 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13520 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13521 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013522
13523 /* Front Pin: output 0 (0x0c) */
13524 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13525 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13526
13527 /* Rear Pin: output 1 (0x0d) */
13528 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13529 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13530
13531 /* CLFE Pin: output 2 (0x0e) */
13532 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13533 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13534
13535 /* Mic (rear) pin: input vref at 80% */
13536 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13537 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13538 /* Front Mic pin: input vref at 80% */
13539 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13540 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13541 /* Line In pin: input */
13542 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13543 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13544 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13545 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13546 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13547 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13548 /* CD pin widget for input */
13549 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13550
13551 /* FIXME: use matrix-type input source selection */
13552 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13553 /* Input mixer */
13554 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13555 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13556 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13557 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020013558
13559 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13560 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13561 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13562 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020013563
13564 /* always trun on EAPD */
13565 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13566 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13567
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013568 { }
13569};
13570
13571static struct hda_verb alc662_sue_init_verbs[] = {
13572 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
13573 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020013574 {}
13575};
13576
13577static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
13578 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13579 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13580 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013581};
13582
Kailang Yang8c427222008-01-10 13:03:59 +010013583/* Set Unsolicited Event*/
13584static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
13585 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13586 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13587 {}
13588};
13589
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013590/*
13591 * generic initialization of ADC, input mixers and output mixers
13592 */
13593static struct hda_verb alc662_auto_init_verbs[] = {
13594 /*
13595 * Unmute ADC and set the default input to mic-in
13596 */
13597 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13598 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13599
13600 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
13601 * mixer widget
13602 * Note: PASD motherboards uses the Line In 2 as the input for front
13603 * panel mic (mic 2)
13604 */
13605 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013606 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13607 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13608 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13609 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13610 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013611
13612 /*
13613 * Set up output mixers (0x0c - 0x0f)
13614 */
13615 /* set vol=0 to output mixers */
13616 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13617 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13618 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13619
13620 /* set up input amps for analog loopback */
13621 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020013622 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13623 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13624 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13625 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13626 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13627 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013628
13629
13630 /* FIXME: use matrix-type input source selection */
13631 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13632 /* Input mixer */
13633 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020013634 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013635 { }
13636};
13637
Kailang Yang6dda9f42008-05-27 12:05:31 +020013638static struct hda_verb alc663_m51va_init_verbs[] = {
13639 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13640 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13641 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
13642
13643 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
13644
13645 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13646 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13647 {}
13648};
13649
13650static struct hda_verb alc663_g71v_init_verbs[] = {
13651 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13652 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
13653 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
13654
13655 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13656 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13657 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
13658
13659 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
13660 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
13661 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
13662 {}
13663};
13664
13665static struct hda_verb alc663_g50v_init_verbs[] = {
13666 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13667 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13668 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
13669
13670 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13671 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13672 {}
13673};
13674
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013675/* capture mixer elements */
13676static struct snd_kcontrol_new alc662_capture_mixer[] = {
13677 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13678 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13679 {
13680 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13681 /* The multiple "Capture Source" controls confuse alsamixer
13682 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013683 */
13684 /* .name = "Capture Source", */
13685 .name = "Input Source",
13686 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010013687 .info = alc662_mux_enum_info,
13688 .get = alc662_mux_enum_get,
13689 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013690 },
13691 { } /* end */
13692};
13693
13694static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
13695{
13696 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013697 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013698
13699 present = snd_hda_codec_read(codec, 0x14, 0,
13700 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013701 bits = present ? HDA_AMP_MUTE : 0;
13702 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13703 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013704}
13705
13706static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
13707{
13708 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013709 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013710
13711 present = snd_hda_codec_read(codec, 0x1b, 0,
13712 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013713 bits = present ? HDA_AMP_MUTE : 0;
13714 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13715 HDA_AMP_MUTE, bits);
13716 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13717 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013718}
13719
13720static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
13721 unsigned int res)
13722{
13723 if ((res >> 26) == ALC880_HP_EVENT)
13724 alc662_lenovo_101e_all_automute(codec);
13725 if ((res >> 26) == ALC880_FRONT_EVENT)
13726 alc662_lenovo_101e_ispeaker_automute(codec);
13727}
13728
Kailang Yang291702f2007-10-16 14:28:03 +020013729static void alc662_eeepc_mic_automute(struct hda_codec *codec)
13730{
13731 unsigned int present;
13732
13733 present = snd_hda_codec_read(codec, 0x18, 0,
13734 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
13735 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13736 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13737 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13738 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13739 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13740 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13741 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13742 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13743}
13744
13745/* unsolicited event for HP jack sensing */
13746static void alc662_eeepc_unsol_event(struct hda_codec *codec,
13747 unsigned int res)
13748{
13749 if ((res >> 26) == ALC880_HP_EVENT)
13750 alc262_hippo1_automute( codec );
13751
13752 if ((res >> 26) == ALC880_MIC_EVENT)
13753 alc662_eeepc_mic_automute(codec);
13754}
13755
13756static void alc662_eeepc_inithook(struct hda_codec *codec)
13757{
13758 alc262_hippo1_automute( codec );
13759 alc662_eeepc_mic_automute(codec);
13760}
13761
Kailang Yang8c427222008-01-10 13:03:59 +010013762static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
13763{
13764 unsigned int mute;
13765 unsigned int present;
13766
13767 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
13768 present = snd_hda_codec_read(codec, 0x14, 0,
13769 AC_VERB_GET_PIN_SENSE, 0);
13770 present = (present & 0x80000000) != 0;
13771 if (present) {
13772 /* mute internal speaker */
13773 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13774 HDA_AMP_MUTE, HDA_AMP_MUTE);
13775 } else {
13776 /* unmute internal speaker if necessary */
13777 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13778 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13779 HDA_AMP_MUTE, mute);
13780 }
13781}
13782
13783/* unsolicited event for HP jack sensing */
13784static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
13785 unsigned int res)
13786{
13787 if ((res >> 26) == ALC880_HP_EVENT)
13788 alc662_eeepc_ep20_automute(codec);
13789}
13790
13791static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
13792{
13793 alc662_eeepc_ep20_automute(codec);
13794}
13795
Kailang Yang6dda9f42008-05-27 12:05:31 +020013796static void alc663_m51va_speaker_automute(struct hda_codec *codec)
13797{
13798 unsigned int present;
13799 unsigned char bits;
13800
13801 present = snd_hda_codec_read(codec, 0x21, 0,
13802 AC_VERB_GET_PIN_SENSE, 0)
13803 & AC_PINSENSE_PRESENCE;
13804 bits = present ? HDA_AMP_MUTE : 0;
13805 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13806 HDA_AMP_MUTE, bits);
13807}
13808
13809static void alc663_m51va_mic_automute(struct hda_codec *codec)
13810{
13811 unsigned int present;
13812
13813 present = snd_hda_codec_read(codec, 0x18, 0,
13814 AC_VERB_GET_PIN_SENSE, 0)
13815 & AC_PINSENSE_PRESENCE;
13816 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13817 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13818 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13819 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13820 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13821 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
13822 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13823 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
13824}
13825
13826static void alc663_m51va_unsol_event(struct hda_codec *codec,
13827 unsigned int res)
13828{
13829 switch (res >> 26) {
13830 case ALC880_HP_EVENT:
13831 alc663_m51va_speaker_automute(codec);
13832 break;
13833 case ALC880_MIC_EVENT:
13834 alc663_m51va_mic_automute(codec);
13835 break;
13836 }
13837}
13838
13839static void alc663_m51va_inithook(struct hda_codec *codec)
13840{
13841 alc663_m51va_speaker_automute(codec);
13842 alc663_m51va_mic_automute(codec);
13843}
13844
13845static void alc663_g71v_hp_automute(struct hda_codec *codec)
13846{
13847 unsigned int present;
13848 unsigned char bits;
13849
13850 present = snd_hda_codec_read(codec, 0x21, 0,
13851 AC_VERB_GET_PIN_SENSE, 0)
13852 & AC_PINSENSE_PRESENCE;
13853 bits = present ? HDA_AMP_MUTE : 0;
13854 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13855 HDA_AMP_MUTE, bits);
13856 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13857 HDA_AMP_MUTE, bits);
13858}
13859
13860static void alc663_g71v_front_automute(struct hda_codec *codec)
13861{
13862 unsigned int present;
13863 unsigned char bits;
13864
13865 present = snd_hda_codec_read(codec, 0x15, 0,
13866 AC_VERB_GET_PIN_SENSE, 0)
13867 & AC_PINSENSE_PRESENCE;
13868 bits = present ? HDA_AMP_MUTE : 0;
13869 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13870 HDA_AMP_MUTE, bits);
13871}
13872
13873static void alc663_g71v_unsol_event(struct hda_codec *codec,
13874 unsigned int res)
13875{
13876 switch (res >> 26) {
13877 case ALC880_HP_EVENT:
13878 alc663_g71v_hp_automute(codec);
13879 break;
13880 case ALC880_FRONT_EVENT:
13881 alc663_g71v_front_automute(codec);
13882 break;
13883 case ALC880_MIC_EVENT:
13884 alc662_eeepc_mic_automute(codec);
13885 break;
13886 }
13887}
13888
13889static void alc663_g71v_inithook(struct hda_codec *codec)
13890{
13891 alc663_g71v_front_automute(codec);
13892 alc663_g71v_hp_automute(codec);
13893 alc662_eeepc_mic_automute(codec);
13894}
13895
13896static void alc663_g50v_unsol_event(struct hda_codec *codec,
13897 unsigned int res)
13898{
13899 switch (res >> 26) {
13900 case ALC880_HP_EVENT:
13901 alc663_m51va_speaker_automute(codec);
13902 break;
13903 case ALC880_MIC_EVENT:
13904 alc662_eeepc_mic_automute(codec);
13905 break;
13906 }
13907}
13908
13909static void alc663_g50v_inithook(struct hda_codec *codec)
13910{
13911 alc663_m51va_speaker_automute(codec);
13912 alc662_eeepc_mic_automute(codec);
13913}
13914
Takashi Iwaicb53c622007-08-10 17:21:45 +020013915#ifdef CONFIG_SND_HDA_POWER_SAVE
13916#define alc662_loopbacks alc880_loopbacks
13917#endif
13918
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013919
13920/* pcm configuration: identiacal with ALC880 */
13921#define alc662_pcm_analog_playback alc880_pcm_analog_playback
13922#define alc662_pcm_analog_capture alc880_pcm_analog_capture
13923#define alc662_pcm_digital_playback alc880_pcm_digital_playback
13924#define alc662_pcm_digital_capture alc880_pcm_digital_capture
13925
13926/*
13927 * configuration and preset
13928 */
13929static const char *alc662_models[ALC662_MODEL_LAST] = {
13930 [ALC662_3ST_2ch_DIG] = "3stack-dig",
13931 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
13932 [ALC662_3ST_6ch] = "3stack-6ch",
13933 [ALC662_5ST_DIG] = "6stack-dig",
13934 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020013935 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010013936 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yang6dda9f42008-05-27 12:05:31 +020013937 [ALC663_ASUS_M51VA] = "m51va",
13938 [ALC663_ASUS_G71V] = "g71v",
13939 [ALC663_ASUS_H13] = "h13",
13940 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013941 [ALC662_AUTO] = "auto",
13942};
13943
13944static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020013945 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
13946 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
13947 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010013948 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020013949 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010013950 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013951 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yang6dda9f42008-05-27 12:05:31 +020013952 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
13953 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
13954 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013955 {}
13956};
13957
13958static struct alc_config_preset alc662_presets[] = {
13959 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013960 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013961 .init_verbs = { alc662_init_verbs },
13962 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13963 .dac_nids = alc662_dac_nids,
13964 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013965 .dig_in_nid = ALC662_DIGIN_NID,
13966 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13967 .channel_mode = alc662_3ST_2ch_modes,
13968 .input_mux = &alc662_capture_source,
13969 },
13970 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013971 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13972 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013973 .init_verbs = { alc662_init_verbs },
13974 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13975 .dac_nids = alc662_dac_nids,
13976 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013977 .dig_in_nid = ALC662_DIGIN_NID,
13978 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13979 .channel_mode = alc662_3ST_6ch_modes,
13980 .need_dac_fix = 1,
13981 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013982 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013983 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013984 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13985 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013986 .init_verbs = { alc662_init_verbs },
13987 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13988 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013989 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13990 .channel_mode = alc662_3ST_6ch_modes,
13991 .need_dac_fix = 1,
13992 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013993 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013994 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013995 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
13996 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013997 .init_verbs = { alc662_init_verbs },
13998 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13999 .dac_nids = alc662_dac_nids,
14000 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014001 .dig_in_nid = ALC662_DIGIN_NID,
14002 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
14003 .channel_mode = alc662_5stack_modes,
14004 .input_mux = &alc662_capture_source,
14005 },
14006 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020014007 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014008 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
14009 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14010 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014011 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
14012 .channel_mode = alc662_3ST_2ch_modes,
14013 .input_mux = &alc662_lenovo_101e_capture_source,
14014 .unsol_event = alc662_lenovo_101e_unsol_event,
14015 .init_hook = alc662_lenovo_101e_all_automute,
14016 },
Kailang Yang291702f2007-10-16 14:28:03 +020014017 [ALC662_ASUS_EEEPC_P701] = {
14018 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
14019 .init_verbs = { alc662_init_verbs,
14020 alc662_eeepc_sue_init_verbs },
14021 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14022 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020014023 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
14024 .channel_mode = alc662_3ST_2ch_modes,
14025 .input_mux = &alc662_eeepc_capture_source,
14026 .unsol_event = alc662_eeepc_unsol_event,
14027 .init_hook = alc662_eeepc_inithook,
14028 },
Kailang Yang8c427222008-01-10 13:03:59 +010014029 [ALC662_ASUS_EEEPC_EP20] = {
14030 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
14031 alc662_chmode_mixer },
14032 .init_verbs = { alc662_init_verbs,
14033 alc662_eeepc_ep20_sue_init_verbs },
14034 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14035 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010014036 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
14037 .channel_mode = alc662_3ST_6ch_modes,
14038 .input_mux = &alc662_lenovo_101e_capture_source,
14039 .unsol_event = alc662_eeepc_ep20_unsol_event,
14040 .init_hook = alc662_eeepc_ep20_inithook,
14041 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020014042 [ALC663_ASUS_M51VA] = {
14043 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
14044 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
14045 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14046 .dac_nids = alc662_dac_nids,
14047 .dig_out_nid = ALC662_DIGOUT_NID,
14048 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
14049 .channel_mode = alc662_3ST_2ch_modes,
14050 .input_mux = &alc663_m51va_capture_source,
14051 .unsol_event = alc663_m51va_unsol_event,
14052 .init_hook = alc663_m51va_inithook,
14053 },
14054 [ALC663_ASUS_G71V] = {
14055 .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
14056 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
14057 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14058 .dac_nids = alc662_dac_nids,
14059 .dig_out_nid = ALC662_DIGOUT_NID,
14060 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
14061 .channel_mode = alc662_3ST_2ch_modes,
14062 .input_mux = &alc662_eeepc_capture_source,
14063 .unsol_event = alc663_g71v_unsol_event,
14064 .init_hook = alc663_g71v_inithook,
14065 },
14066 [ALC663_ASUS_H13] = {
14067 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
14068 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
14069 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14070 .dac_nids = alc662_dac_nids,
14071 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
14072 .channel_mode = alc662_3ST_2ch_modes,
14073 .input_mux = &alc663_m51va_capture_source,
14074 .unsol_event = alc663_m51va_unsol_event,
14075 .init_hook = alc663_m51va_inithook,
14076 },
14077 [ALC663_ASUS_G50V] = {
14078 .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
14079 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
14080 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
14081 .dac_nids = alc662_dac_nids,
14082 .dig_out_nid = ALC662_DIGOUT_NID,
14083 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
14084 .channel_mode = alc662_3ST_6ch_modes,
14085 .input_mux = &alc663_capture_source,
14086 .unsol_event = alc663_g50v_unsol_event,
14087 .init_hook = alc663_g50v_inithook,
14088 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014089};
14090
14091
14092/*
14093 * BIOS auto configuration
14094 */
14095
14096/* add playback controls from the parsed DAC table */
14097static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
14098 const struct auto_pin_cfg *cfg)
14099{
14100 char name[32];
14101 static const char *chname[4] = {
14102 "Front", "Surround", NULL /*CLFE*/, "Side"
14103 };
14104 hda_nid_t nid;
14105 int i, err;
14106
14107 for (i = 0; i < cfg->line_outs; i++) {
14108 if (!spec->multiout.dac_nids[i])
14109 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020014110 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014111 if (i == 2) {
14112 /* Center/LFE */
14113 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14114 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014115 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
14116 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014117 if (err < 0)
14118 return err;
14119 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14120 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014121 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
14122 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014123 if (err < 0)
14124 return err;
14125 err = add_control(spec, ALC_CTL_BIND_MUTE,
14126 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014127 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
14128 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014129 if (err < 0)
14130 return err;
14131 err = add_control(spec, ALC_CTL_BIND_MUTE,
14132 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014133 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
14134 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014135 if (err < 0)
14136 return err;
14137 } else {
14138 sprintf(name, "%s Playback Volume", chname[i]);
14139 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014140 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
14141 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014142 if (err < 0)
14143 return err;
14144 sprintf(name, "%s Playback Switch", chname[i]);
14145 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014146 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
14147 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014148 if (err < 0)
14149 return err;
14150 }
14151 }
14152 return 0;
14153}
14154
14155/* add playback controls for speaker and HP outputs */
14156static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
14157 const char *pfx)
14158{
14159 hda_nid_t nid;
14160 int err;
14161 char name[32];
14162
14163 if (!pin)
14164 return 0;
14165
14166 if (alc880_is_fixed_pin(pin)) {
14167 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14168 /* printk("DAC nid=%x\n",nid); */
14169 /* specify the DAC as the extra output */
14170 if (!spec->multiout.hp_nid)
14171 spec->multiout.hp_nid = nid;
14172 else
14173 spec->multiout.extra_out_nid[0] = nid;
14174 /* control HP volume/switch on the output mixer amp */
14175 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14176 sprintf(name, "%s Playback Volume", pfx);
14177 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14178 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
14179 if (err < 0)
14180 return err;
14181 sprintf(name, "%s Playback Switch", pfx);
14182 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14183 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
14184 if (err < 0)
14185 return err;
14186 } else if (alc880_is_multi_pin(pin)) {
14187 /* set manual connection */
14188 /* we have only a switch on HP-out PIN */
14189 sprintf(name, "%s Playback Switch", pfx);
14190 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14191 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14192 if (err < 0)
14193 return err;
14194 }
14195 return 0;
14196}
14197
14198/* create playback/capture controls for input pins */
14199static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
14200 const struct auto_pin_cfg *cfg)
14201{
14202 struct hda_input_mux *imux = &spec->private_imux;
14203 int i, err, idx;
14204
14205 for (i = 0; i < AUTO_PIN_LAST; i++) {
14206 if (alc880_is_input_pin(cfg->input_pins[i])) {
14207 idx = alc880_input_pin_idx(cfg->input_pins[i]);
14208 err = new_analog_input(spec, cfg->input_pins[i],
14209 auto_pin_cfg_labels[i],
14210 idx, 0x0b);
14211 if (err < 0)
14212 return err;
14213 imux->items[imux->num_items].label =
14214 auto_pin_cfg_labels[i];
14215 imux->items[imux->num_items].index =
14216 alc880_input_pin_idx(cfg->input_pins[i]);
14217 imux->num_items++;
14218 }
14219 }
14220 return 0;
14221}
14222
14223static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
14224 hda_nid_t nid, int pin_type,
14225 int dac_idx)
14226{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014227 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014228 /* need the manual connection? */
14229 if (alc880_is_multi_pin(nid)) {
14230 struct alc_spec *spec = codec->spec;
14231 int idx = alc880_multi_pin_idx(nid);
14232 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
14233 AC_VERB_SET_CONNECT_SEL,
14234 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
14235 }
14236}
14237
14238static void alc662_auto_init_multi_out(struct hda_codec *codec)
14239{
14240 struct alc_spec *spec = codec->spec;
14241 int i;
14242
Kailang Yang8c427222008-01-10 13:03:59 +010014243 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014244 for (i = 0; i <= HDA_SIDE; i++) {
14245 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014246 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014247 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014248 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014249 i);
14250 }
14251}
14252
14253static void alc662_auto_init_hp_out(struct hda_codec *codec)
14254{
14255 struct alc_spec *spec = codec->spec;
14256 hda_nid_t pin;
14257
14258 pin = spec->autocfg.hp_pins[0];
14259 if (pin) /* connect to front */
14260 /* use dac 0 */
14261 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014262 pin = spec->autocfg.speaker_pins[0];
14263 if (pin)
14264 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014265}
14266
14267#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
14268#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
14269
14270static void alc662_auto_init_analog_input(struct hda_codec *codec)
14271{
14272 struct alc_spec *spec = codec->spec;
14273 int i;
14274
14275 for (i = 0; i < AUTO_PIN_LAST; i++) {
14276 hda_nid_t nid = spec->autocfg.input_pins[i];
14277 if (alc662_is_input_pin(nid)) {
14278 snd_hda_codec_write(codec, nid, 0,
14279 AC_VERB_SET_PIN_WIDGET_CONTROL,
14280 (i <= AUTO_PIN_FRONT_MIC ?
14281 PIN_VREF80 : PIN_IN));
14282 if (nid != ALC662_PIN_CD_NID)
14283 snd_hda_codec_write(codec, nid, 0,
14284 AC_VERB_SET_AMP_GAIN_MUTE,
14285 AMP_OUT_MUTE);
14286 }
14287 }
14288}
14289
14290static int alc662_parse_auto_config(struct hda_codec *codec)
14291{
14292 struct alc_spec *spec = codec->spec;
14293 int err;
14294 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
14295
14296 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14297 alc662_ignore);
14298 if (err < 0)
14299 return err;
14300 if (!spec->autocfg.line_outs)
14301 return 0; /* can't find valid BIOS pin config */
14302
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014303 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14304 if (err < 0)
14305 return err;
14306 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
14307 if (err < 0)
14308 return err;
14309 err = alc662_auto_create_extra_out(spec,
14310 spec->autocfg.speaker_pins[0],
14311 "Speaker");
14312 if (err < 0)
14313 return err;
14314 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
14315 "Headphone");
14316 if (err < 0)
14317 return err;
14318 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
14319 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014320 return err;
14321
14322 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14323
14324 if (spec->autocfg.dig_out_pin)
14325 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
14326
14327 if (spec->kctl_alloc)
14328 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
14329
14330 spec->num_mux_defs = 1;
14331 spec->input_mux = &spec->private_imux;
14332
Takashi Iwai8c87286f2007-06-19 12:11:16 +020014333 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014334 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
14335 spec->num_mixers++;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020014336 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014337}
14338
14339/* additional initialization for auto-configuration model */
14340static void alc662_auto_init(struct hda_codec *codec)
14341{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014342 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014343 alc662_auto_init_multi_out(codec);
14344 alc662_auto_init_hp_out(codec);
14345 alc662_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014346 if (spec->unsol_event)
14347 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014348}
14349
14350static int patch_alc662(struct hda_codec *codec)
14351{
14352 struct alc_spec *spec;
14353 int err, board_config;
14354
14355 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14356 if (!spec)
14357 return -ENOMEM;
14358
14359 codec->spec = spec;
14360
14361 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
14362 alc662_models,
14363 alc662_cfg_tbl);
14364 if (board_config < 0) {
14365 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
14366 "trying auto-probe from BIOS...\n");
14367 board_config = ALC662_AUTO;
14368 }
14369
14370 if (board_config == ALC662_AUTO) {
14371 /* automatic parse from the BIOS config */
14372 err = alc662_parse_auto_config(codec);
14373 if (err < 0) {
14374 alc_free(codec);
14375 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020014376 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014377 printk(KERN_INFO
14378 "hda_codec: Cannot set up configuration "
14379 "from BIOS. Using base mode...\n");
14380 board_config = ALC662_3ST_2ch_DIG;
14381 }
14382 }
14383
14384 if (board_config != ALC662_AUTO)
14385 setup_preset(spec, &alc662_presets[board_config]);
14386
Kailang Yang6dda9f42008-05-27 12:05:31 +020014387 if (codec->vendor_id == 0x10ec0663) {
14388 spec->stream_name_analog = "ALC663 Analog";
14389 spec->stream_name_digital = "ALC663 Digital";
14390 } else {
14391 spec->stream_name_analog = "ALC662 Analog";
14392 spec->stream_name_digital = "ALC662 Digital";
14393 }
14394
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014395 spec->stream_analog_playback = &alc662_pcm_analog_playback;
14396 spec->stream_analog_capture = &alc662_pcm_analog_capture;
14397
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014398 spec->stream_digital_playback = &alc662_pcm_digital_playback;
14399 spec->stream_digital_capture = &alc662_pcm_digital_capture;
14400
Takashi Iwaie1406342008-02-11 18:32:32 +010014401 spec->adc_nids = alc662_adc_nids;
14402 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
14403 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014404
Takashi Iwai2134ea42008-01-10 16:53:55 +010014405 spec->vmaster_nid = 0x02;
14406
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014407 codec->patch_ops = alc_patch_ops;
14408 if (board_config == ALC662_AUTO)
14409 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014410#ifdef CONFIG_SND_HDA_POWER_SAVE
14411 if (!spec->loopback.amplist)
14412 spec->loopback.amplist = alc662_loopbacks;
14413#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014414
14415 return 0;
14416}
14417
14418/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070014419 * patch entries
14420 */
14421struct hda_codec_preset snd_hda_preset_realtek[] = {
14422 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014423 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014424 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020014425 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014426 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014427 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014428 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014429 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
14430 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
14431 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014432 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
14433 .patch = patch_alc883 },
14434 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
14435 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020014436 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014437 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070014438 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014439 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020014440 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020014441 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010014442 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014443 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014444 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070014445 {} /* terminator */
14446};