blob: a5047322174374ee8b4cc15d3ea28c80799e7513 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010033#include "hda_patch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi 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 Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010081#ifdef CONFIG_SND_DEBUG
82 ALC260_TEST,
83#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010084 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020085 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Kailang Yangdf694da2005-12-05 19:42:22 +010088/* ALC262 models */
89enum {
90 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020091 ALC262_HIPPO,
92 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010093 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020094 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010095 ALC262_HP_BPC_D7000_WL,
96 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010097 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010098 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020099 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200100 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200101 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200102 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100103 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200104 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200105 ALC262_TOSHIBA_S06,
Kailang Yangdf694da2005-12-05 19:42:22 +0100106 ALC262_AUTO,
107 ALC262_MODEL_LAST /* last tag */
108};
109
Kailang Yanga361d842007-06-05 12:30:55 +0200110/* ALC268 models */
111enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200112 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200113 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200114 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200115 ALC268_ACER,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200116 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100117 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100118 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100119#ifdef CONFIG_SND_DEBUG
120 ALC268_TEST,
121#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200122 ALC268_AUTO,
123 ALC268_MODEL_LAST /* last tag */
124};
125
Kailang Yangf6a92242007-12-13 16:52:54 +0100126/* ALC269 models */
127enum {
128 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200129 ALC269_QUANTA_FL1,
Kailang Yangf53281e2008-07-18 12:36:43 +0200130 ALC269_ASUS_EEEPC_P703,
131 ALC269_ASUS_EEEPC_P901,
Kailang Yangf6a92242007-12-13 16:52:54 +0100132 ALC269_AUTO,
133 ALC269_MODEL_LAST /* last tag */
134};
135
Kailang Yangdf694da2005-12-05 19:42:22 +0100136/* ALC861 models */
137enum {
138 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200139 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100140 ALC861_3ST_DIG,
141 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200142 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200143 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200144 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100145 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100146 ALC861_AUTO,
147 ALC861_MODEL_LAST,
148};
149
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100150/* ALC861-VD models */
151enum {
152 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200153 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100154 ALC861VD_3ST,
155 ALC861VD_3ST_DIG,
156 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200157 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200158 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200159 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160 ALC861VD_AUTO,
161 ALC861VD_MODEL_LAST,
162};
163
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200164/* ALC662 models */
165enum {
166 ALC662_3ST_2ch_DIG,
167 ALC662_3ST_6ch_DIG,
168 ALC662_3ST_6ch,
169 ALC662_5ST_DIG,
170 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200171 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100172 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200173 ALC663_ASUS_M51VA,
174 ALC663_ASUS_G71V,
175 ALC663_ASUS_H13,
176 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200177 ALC662_ECS,
178 ALC663_ASUS_MODE1,
179 ALC662_ASUS_MODE2,
180 ALC663_ASUS_MODE3,
181 ALC663_ASUS_MODE4,
182 ALC663_ASUS_MODE5,
183 ALC663_ASUS_MODE6,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200184 ALC662_AUTO,
185 ALC662_MODEL_LAST,
186};
187
Kailang Yangdf694da2005-12-05 19:42:22 +0100188/* ALC882 models */
189enum {
190 ALC882_3ST_DIG,
191 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200192 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200193 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200194 ALC882_TARGA,
195 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200196 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100197 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200198 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200199 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200200 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100201 ALC882_MODEL_LAST,
202};
203
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200204/* ALC883 models */
205enum {
206 ALC883_3ST_2ch_DIG,
207 ALC883_3ST_6ch_DIG,
208 ALC883_3ST_6ch,
209 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200210 ALC883_TARGA_DIG,
211 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200212 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200213 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200214 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200215 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100216 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200217 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200218 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200219 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200220 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200221 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200222 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100223 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100224 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100225 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100226 ALC883_FUJITSU_PI2515,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200227 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200228 ALC888_ASUS_M90V,
229 ALC888_ASUS_EEE1601,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200230 ALC883_AUTO,
231 ALC883_MODEL_LAST,
232};
233
Kailang Yangdf694da2005-12-05 19:42:22 +0100234/* for GPIO Poll */
235#define GPIO_MASK 0x03
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237struct alc_spec {
238 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100239 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 unsigned int num_mixers;
241
Kailang Yangdf694da2005-12-05 19:42:22 +0100242 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200243 * don't forget NULL
244 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200245 */
246 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Takashi Iwai16ded522005-06-10 19:58:24 +0200248 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 struct hda_pcm_stream *stream_analog_playback;
250 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100251 struct hda_pcm_stream *stream_analog_alt_playback;
252 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200254 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 struct hda_pcm_stream *stream_digital_playback;
256 struct hda_pcm_stream *stream_digital_capture;
257
258 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200259 struct hda_multi_out multiout; /* playback set-up
260 * max_channels, dacs must be set
261 * dig_out_nid and hp_nid are optional
262 */
Takashi Iwai63300792008-01-24 15:31:36 +0100263 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 /* capture */
266 unsigned int num_adc_nids;
267 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100268 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200269 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200272 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 const struct hda_input_mux *input_mux;
274 unsigned int cur_mux[3];
275
276 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100277 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200279 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100282 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200283
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200284 /* dynamic controls, init_verbs and input_mux */
285 struct auto_pin_cfg autocfg;
286 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100287 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200288 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200289 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100290
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100291 /* hooks */
292 void (*init_hook)(struct hda_codec *codec);
293 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
294
Takashi Iwai834be882006-03-01 14:16:17 +0100295 /* for pin sensing */
296 unsigned int sense_updated: 1;
297 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100298 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200299
Takashi Iwai2134ea42008-01-10 16:53:55 +0100300 /* for virtual master */
301 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200302#ifdef CONFIG_SND_HDA_POWER_SAVE
303 struct hda_loopback_check loopback;
304#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200305
306 /* for PLL fix */
307 hda_nid_t pll_nid;
308 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100309};
310
311/*
312 * configuration template - to be copied to the spec instance
313 */
314struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200315 struct snd_kcontrol_new *mixers[5]; /* should be identical size
316 * with spec
317 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100318 const struct hda_verb *init_verbs[5];
319 unsigned int num_dacs;
320 hda_nid_t *dac_nids;
321 hda_nid_t dig_out_nid; /* optional */
322 hda_nid_t hp_nid; /* optional */
323 unsigned int num_adc_nids;
324 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100325 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100326 hda_nid_t dig_in_nid;
327 unsigned int num_channel_mode;
328 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200329 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200330 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100331 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100332 void (*unsol_event)(struct hda_codec *, unsigned int);
333 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200334#ifdef CONFIG_SND_HDA_POWER_SAVE
335 struct hda_amp_list *loopbacks;
336#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337};
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340/*
341 * input MUX handling
342 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200343static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
347 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200348 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
349 if (mux_idx >= spec->num_mux_defs)
350 mux_idx = 0;
351 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200354static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
355 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
358 struct alc_spec *spec = codec->spec;
359 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
360
361 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
362 return 0;
363}
364
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200365static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
369 struct alc_spec *spec = codec->spec;
370 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200371 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100372 hda_nid_t nid = spec->capsrc_nids ?
373 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200374 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100375 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
377
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379/*
380 * channel mode setting
381 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200382static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
383 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
386 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100387 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
388 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
390
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200391static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
392 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393{
394 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
395 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100396 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200397 spec->num_channel_mode,
398 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200401static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
402 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
405 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200406 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
407 spec->num_channel_mode,
408 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200409 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200410 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
411 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100415 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200416 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100417 * being part of a format specifier. Maximum allowed length of a value is
418 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100419 *
420 * Note: some retasking pin complexes seem to ignore requests for input
421 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
422 * are requested. Therefore order this list so that this behaviour will not
423 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200424 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
425 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200426 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100427static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100428 "Mic 50pc bias", "Mic 80pc bias",
429 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100430};
431static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100432 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100433};
434/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200435 * in the pin being assumed to be exclusively an input or an output pin. In
436 * addition, "input" pins may or may not process the mic bias option
437 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
438 * accept requests for bias as of chip versions up to March 2006) and/or
439 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100440 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200441#define ALC_PIN_DIR_IN 0x00
442#define ALC_PIN_DIR_OUT 0x01
443#define ALC_PIN_DIR_INOUT 0x02
444#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
445#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100446
Kailang Yangea1fb292008-08-26 12:58:38 +0200447/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100448 * For each direction the minimum and maximum values are given.
449 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200450static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100451 { 0, 2 }, /* ALC_PIN_DIR_IN */
452 { 3, 4 }, /* ALC_PIN_DIR_OUT */
453 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200454 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
455 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100456};
457#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
458#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
459#define alc_pin_mode_n_items(_dir) \
460 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
461
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200462static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200464{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100465 unsigned int item_num = uinfo->value.enumerated.item;
466 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
467
468 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200469 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100470 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
471
472 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
473 item_num = alc_pin_mode_min(dir);
474 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200475 return 0;
476}
477
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200478static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
479 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200480{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100481 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200482 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
483 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100484 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200485 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200486 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
487 AC_VERB_GET_PIN_WIDGET_CONTROL,
488 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200489
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100490 /* Find enumerated value for current pinctl setting */
491 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200492 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100493 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200494 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100495 return 0;
496}
497
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200498static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100500{
501 signed int change;
502 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
503 hda_nid_t nid = kcontrol->private_value & 0xffff;
504 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
505 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200506 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
507 AC_VERB_GET_PIN_WIDGET_CONTROL,
508 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100509
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200510 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100511 val = alc_pin_mode_min(dir);
512
513 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100514 if (change) {
515 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200516 snd_hda_codec_write_cache(codec, nid, 0,
517 AC_VERB_SET_PIN_WIDGET_CONTROL,
518 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100519
Kailang Yangea1fb292008-08-26 12:58:38 +0200520 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100521 * for the requested pin mode. Enum values of 2 or less are
522 * input modes.
523 *
524 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200525 * reduces noise slightly (particularly on input) so we'll
526 * do it. However, having both input and output buffers
527 * enabled simultaneously doesn't seem to be problematic if
528 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100529 */
530 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200531 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
532 HDA_AMP_MUTE, HDA_AMP_MUTE);
533 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
534 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100535 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200536 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
537 HDA_AMP_MUTE, HDA_AMP_MUTE);
538 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
539 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100540 }
541 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200542 return change;
543}
544
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100545#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200546 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100547 .info = alc_pin_mode_info, \
548 .get = alc_pin_mode_get, \
549 .put = alc_pin_mode_put, \
550 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100551
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100552/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
553 * together using a mask with more than one bit set. This control is
554 * currently used only by the ALC260 test model. At this stage they are not
555 * needed for any "production" models.
556 */
557#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200558#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200559
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200560static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
561 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100562{
563 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
564 hda_nid_t nid = kcontrol->private_value & 0xffff;
565 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
566 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200567 unsigned int val = snd_hda_codec_read(codec, nid, 0,
568 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100569
570 *valp = (val & mask) != 0;
571 return 0;
572}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200573static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100575{
576 signed int change;
577 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
578 hda_nid_t nid = kcontrol->private_value & 0xffff;
579 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
580 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200581 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
582 AC_VERB_GET_GPIO_DATA,
583 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100584
585 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200586 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
587 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100588 gpio_data &= ~mask;
589 else
590 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200591 snd_hda_codec_write_cache(codec, nid, 0,
592 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100593
594 return change;
595}
596#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
597 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
598 .info = alc_gpio_data_info, \
599 .get = alc_gpio_data_get, \
600 .put = alc_gpio_data_put, \
601 .private_value = nid | (mask<<16) }
602#endif /* CONFIG_SND_DEBUG */
603
Jonathan Woithe92621f12006-02-28 11:47:47 +0100604/* A switch control to allow the enabling of the digital IO pins on the
605 * ALC260. This is incredibly simplistic; the intention of this control is
606 * to provide something in the test model allowing digital outputs to be
607 * identified if present. If models are found which can utilise these
608 * outputs a more complete mixer control can be devised for those models if
609 * necessary.
610 */
611#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200612#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200613
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200614static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
615 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100616{
617 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
618 hda_nid_t nid = kcontrol->private_value & 0xffff;
619 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
620 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200621 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100622 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100623
624 *valp = (val & mask) != 0;
625 return 0;
626}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200627static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
628 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100629{
630 signed int change;
631 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
632 hda_nid_t nid = kcontrol->private_value & 0xffff;
633 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
634 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200635 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100636 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200637 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100638
639 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200640 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100641 if (val==0)
642 ctrl_data &= ~mask;
643 else
644 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200645 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
646 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100647
648 return change;
649}
650#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
651 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
652 .info = alc_spdif_ctrl_info, \
653 .get = alc_spdif_ctrl_get, \
654 .put = alc_spdif_ctrl_put, \
655 .private_value = nid | (mask<<16) }
656#endif /* CONFIG_SND_DEBUG */
657
Jonathan Woithef8225f62008-01-08 12:16:54 +0100658/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
659 * Again, this is only used in the ALC26x test models to help identify when
660 * the EAPD line must be asserted for features to work.
661 */
662#ifdef CONFIG_SND_DEBUG
663#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
664
665static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
666 struct snd_ctl_elem_value *ucontrol)
667{
668 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
669 hda_nid_t nid = kcontrol->private_value & 0xffff;
670 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
671 long *valp = ucontrol->value.integer.value;
672 unsigned int val = snd_hda_codec_read(codec, nid, 0,
673 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
674
675 *valp = (val & mask) != 0;
676 return 0;
677}
678
679static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
680 struct snd_ctl_elem_value *ucontrol)
681{
682 int change;
683 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
684 hda_nid_t nid = kcontrol->private_value & 0xffff;
685 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
686 long val = *ucontrol->value.integer.value;
687 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
688 AC_VERB_GET_EAPD_BTLENABLE,
689 0x00);
690
691 /* Set/unset the masked control bit(s) as needed */
692 change = (!val ? 0 : mask) != (ctrl_data & mask);
693 if (!val)
694 ctrl_data &= ~mask;
695 else
696 ctrl_data |= mask;
697 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
698 ctrl_data);
699
700 return change;
701}
702
703#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
704 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
705 .info = alc_eapd_ctrl_info, \
706 .get = alc_eapd_ctrl_get, \
707 .put = alc_eapd_ctrl_put, \
708 .private_value = nid | (mask<<16) }
709#endif /* CONFIG_SND_DEBUG */
710
Kailang Yangdf694da2005-12-05 19:42:22 +0100711/*
712 * set up from the preset table
713 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200714static void setup_preset(struct alc_spec *spec,
715 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100716{
717 int i;
718
719 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
720 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200721 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
722 i++)
723 spec->init_verbs[spec->num_init_verbs++] =
724 preset->init_verbs[i];
Kailang Yangea1fb292008-08-26 12:58:38 +0200725
Kailang Yangdf694da2005-12-05 19:42:22 +0100726 spec->channel_mode = preset->channel_mode;
727 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200728 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100729
730 spec->multiout.max_channels = spec->channel_mode[0].channels;
731
732 spec->multiout.num_dacs = preset->num_dacs;
733 spec->multiout.dac_nids = preset->dac_nids;
734 spec->multiout.dig_out_nid = preset->dig_out_nid;
735 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200736
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200737 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200738 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200739 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100740 spec->input_mux = preset->input_mux;
741
742 spec->num_adc_nids = preset->num_adc_nids;
743 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100744 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100745 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100746
747 spec->unsol_event = preset->unsol_event;
748 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200749#ifdef CONFIG_SND_HDA_POWER_SAVE
750 spec->loopback.amplist = preset->loopbacks;
751#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100752}
753
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200754/* Enable GPIO mask and set output */
755static struct hda_verb alc_gpio1_init_verbs[] = {
756 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
757 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
758 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
759 { }
760};
761
762static struct hda_verb alc_gpio2_init_verbs[] = {
763 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
764 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
765 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
766 { }
767};
768
Kailang Yangbdd148a2007-05-08 15:19:08 +0200769static struct hda_verb alc_gpio3_init_verbs[] = {
770 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
771 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
772 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
773 { }
774};
775
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200776/*
777 * Fix hardware PLL issue
778 * On some codecs, the analog PLL gating control must be off while
779 * the default value is 1.
780 */
781static void alc_fix_pll(struct hda_codec *codec)
782{
783 struct alc_spec *spec = codec->spec;
784 unsigned int val;
785
786 if (!spec->pll_nid)
787 return;
788 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
789 spec->pll_coef_idx);
790 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
791 AC_VERB_GET_PROC_COEF, 0);
792 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
793 spec->pll_coef_idx);
794 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
795 val & ~(1 << spec->pll_coef_bit));
796}
797
798static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
799 unsigned int coef_idx, unsigned int coef_bit)
800{
801 struct alc_spec *spec = codec->spec;
802 spec->pll_nid = nid;
803 spec->pll_coef_idx = coef_idx;
804 spec->pll_coef_bit = coef_bit;
805 alc_fix_pll(codec);
806}
807
Kailang Yangc9b58002007-10-16 14:30:01 +0200808static void alc_sku_automute(struct hda_codec *codec)
809{
810 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200811 unsigned int present;
812 unsigned int hp_nid = spec->autocfg.hp_pins[0];
813 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
814
815 /* need to execute and sync at first */
816 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
817 present = snd_hda_codec_read(codec, hp_nid, 0,
818 AC_VERB_GET_PIN_SENSE, 0);
819 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100820 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
821 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200822}
823
824/* unsolicited event for HP jack sensing */
825static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
826{
827 if (codec->vendor_id == 0x10ec0880)
828 res >>= 28;
829 else
830 res >>= 26;
831 if (res != ALC880_HP_EVENT)
832 return;
833
834 alc_sku_automute(codec);
835}
836
Kailang Yangf9423e72008-05-27 12:32:25 +0200837/* additional initialization for ALC888 variants */
838static void alc888_coef_init(struct hda_codec *codec)
839{
840 unsigned int tmp;
841
842 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
843 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
844 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
845 if ((tmp & 0xf0) == 2)
846 /* alc888S-VC */
847 snd_hda_codec_read(codec, 0x20, 0,
848 AC_VERB_SET_PROC_COEF, 0x830);
849 else
850 /* alc888-VB */
851 snd_hda_codec_read(codec, 0x20, 0,
852 AC_VERB_SET_PROC_COEF, 0x3030);
853}
854
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200855/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
856 * 31 ~ 16 : Manufacture ID
857 * 15 ~ 8 : SKU ID
858 * 7 ~ 0 : Assembly ID
859 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
860 */
861static void alc_subsystem_id(struct hda_codec *codec,
862 unsigned int porta, unsigned int porte,
863 unsigned int portd)
864{
Kailang Yangc9b58002007-10-16 14:30:01 +0200865 unsigned int ass, tmp, i;
866 unsigned nid;
867 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200868
Kailang Yangc9b58002007-10-16 14:30:01 +0200869 ass = codec->subsystem_id & 0xffff;
870 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
871 goto do_sku;
872
Kailang Yangea1fb292008-08-26 12:58:38 +0200873 /*
Kailang Yangc9b58002007-10-16 14:30:01 +0200874 * 31~30 : port conetcivity
875 * 29~21 : reserve
876 * 20 : PCBEEP input
877 * 19~16 : Check sum (15:1)
878 * 15~1 : Custom
879 * 0 : override
880 */
881 nid = 0x1d;
882 if (codec->vendor_id == 0x10ec0260)
883 nid = 0x17;
884 ass = snd_hda_codec_read(codec, nid, 0,
885 AC_VERB_GET_CONFIG_DEFAULT, 0);
886 if (!(ass & 1) && !(ass & 0x100000))
887 return;
888 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200889 return;
890
Kailang Yangc9b58002007-10-16 14:30:01 +0200891 /* check sum */
892 tmp = 0;
893 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100894 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200895 tmp++;
896 }
897 if (((ass >> 16) & 0xf) != tmp)
898 return;
899do_sku:
900 /*
901 * 0 : override
902 * 1 : Swap Jack
903 * 2 : 0 --> Desktop, 1 --> Laptop
904 * 3~5 : External Amplifier control
905 * 7~6 : Reserved
906 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200907 tmp = (ass & 0x38) >> 3; /* external Amp control */
908 switch (tmp) {
909 case 1:
910 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
911 break;
912 case 3:
913 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
914 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200915 case 7:
916 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
917 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200918 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200919 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200920 case 0x10ec0260:
921 snd_hda_codec_write(codec, 0x0f, 0,
922 AC_VERB_SET_EAPD_BTLENABLE, 2);
923 snd_hda_codec_write(codec, 0x10, 0,
924 AC_VERB_SET_EAPD_BTLENABLE, 2);
925 break;
926 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200927 case 0x10ec0267:
928 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200929 case 0x10ec0269:
Kailang Yangf9423e72008-05-27 12:32:25 +0200930 case 0x10ec0660:
931 case 0x10ec0662:
932 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +0200933 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200934 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200935 snd_hda_codec_write(codec, 0x14, 0,
936 AC_VERB_SET_EAPD_BTLENABLE, 2);
937 snd_hda_codec_write(codec, 0x15, 0,
938 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200939 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200940 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200941 switch (codec->vendor_id) {
942 case 0x10ec0260:
943 snd_hda_codec_write(codec, 0x1a, 0,
944 AC_VERB_SET_COEF_INDEX, 7);
945 tmp = snd_hda_codec_read(codec, 0x1a, 0,
946 AC_VERB_GET_PROC_COEF, 0);
947 snd_hda_codec_write(codec, 0x1a, 0,
948 AC_VERB_SET_COEF_INDEX, 7);
949 snd_hda_codec_write(codec, 0x1a, 0,
950 AC_VERB_SET_PROC_COEF,
951 tmp | 0x2010);
952 break;
953 case 0x10ec0262:
954 case 0x10ec0880:
955 case 0x10ec0882:
956 case 0x10ec0883:
957 case 0x10ec0885:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200958 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +0200959 snd_hda_codec_write(codec, 0x20, 0,
960 AC_VERB_SET_COEF_INDEX, 7);
961 tmp = snd_hda_codec_read(codec, 0x20, 0,
962 AC_VERB_GET_PROC_COEF, 0);
963 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200964 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200965 snd_hda_codec_write(codec, 0x20, 0,
966 AC_VERB_SET_PROC_COEF,
967 tmp | 0x2010);
968 break;
Kailang Yangf9423e72008-05-27 12:32:25 +0200969 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +0200970 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +0200971 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200972 case 0x10ec0267:
973 case 0x10ec0268:
974 snd_hda_codec_write(codec, 0x20, 0,
975 AC_VERB_SET_COEF_INDEX, 7);
976 tmp = snd_hda_codec_read(codec, 0x20, 0,
977 AC_VERB_GET_PROC_COEF, 0);
978 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200979 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200980 snd_hda_codec_write(codec, 0x20, 0,
981 AC_VERB_SET_PROC_COEF,
982 tmp | 0x3000);
983 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200984 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200985 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200986 break;
987 }
Kailang Yangea1fb292008-08-26 12:58:38 +0200988
Kailang Yang8c427222008-01-10 13:03:59 +0100989 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200990 * when the external headphone out jack is plugged"
991 */
Kailang Yang8c427222008-01-10 13:03:59 +0100992 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200993 return;
994 /*
995 * 10~8 : Jack location
996 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
997 * 14~13: Resvered
998 * 15 : 1 --> enable the function "Mute internal speaker
999 * when the external headphone out jack is plugged"
1000 */
1001 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001002 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001003 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001004 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001005 else
1006 return;
1007 }
1008
1009 if (!spec->autocfg.hp_pins[0]) {
1010 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1011 if (tmp == 0)
1012 spec->autocfg.hp_pins[0] = porta;
1013 else if (tmp == 1)
1014 spec->autocfg.hp_pins[0] = porte;
1015 else if (tmp == 2)
1016 spec->autocfg.hp_pins[0] = portd;
1017 else
1018 return;
1019 }
1020
1021 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1022 AC_VERB_SET_UNSOLICITED_ENABLE,
1023 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangea1fb292008-08-26 12:58:38 +02001024
Kailang Yangc9b58002007-10-16 14:30:01 +02001025 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001026}
1027
Takashi Iwai41e41f12005-06-08 14:48:49 +02001028/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001029 * Fix-up pin default configurations
1030 */
1031
1032struct alc_pincfg {
1033 hda_nid_t nid;
1034 u32 val;
1035};
1036
1037static void alc_fix_pincfg(struct hda_codec *codec,
1038 const struct snd_pci_quirk *quirk,
1039 const struct alc_pincfg **pinfix)
1040{
1041 const struct alc_pincfg *cfg;
1042
1043 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1044 if (!quirk)
1045 return;
1046
1047 cfg = pinfix[quirk->value];
1048 for (; cfg->nid; cfg++) {
1049 int i;
1050 u32 val = cfg->val;
1051 for (i = 0; i < 4; i++) {
1052 snd_hda_codec_write(codec, cfg->nid, 0,
1053 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
1054 val & 0xff);
1055 val >>= 8;
1056 }
1057 }
1058}
1059
1060/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001061 * ALC880 3-stack model
1062 *
1063 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001064 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1065 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 */
1067
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001068static hda_nid_t alc880_dac_nids[4] = {
1069 /* front, rear, clfe, rear_surr */
1070 0x02, 0x05, 0x04, 0x03
1071};
1072
1073static hda_nid_t alc880_adc_nids[3] = {
1074 /* ADC0-2 */
1075 0x07, 0x08, 0x09,
1076};
1077
1078/* The datasheet says the node 0x07 is connected from inputs,
1079 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001080 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001082static hda_nid_t alc880_adc_nids_alt[2] = {
1083 /* ADC1-2 */
1084 0x08, 0x09,
1085};
1086
1087#define ALC880_DIGOUT_NID 0x06
1088#define ALC880_DIGIN_NID 0x0a
1089
1090static struct hda_input_mux alc880_capture_source = {
1091 .num_items = 4,
1092 .items = {
1093 { "Mic", 0x0 },
1094 { "Front Mic", 0x3 },
1095 { "Line", 0x2 },
1096 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001098};
1099
1100/* channel source setting (2/6 channel selection for 3-stack) */
1101/* 2ch mode */
1102static struct hda_verb alc880_threestack_ch2_init[] = {
1103 /* set line-in to input, mute it */
1104 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1105 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1106 /* set mic-in to input vref 80%, mute it */
1107 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1108 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 { } /* end */
1110};
1111
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001112/* 6ch mode */
1113static struct hda_verb alc880_threestack_ch6_init[] = {
1114 /* set line-in to output, unmute it */
1115 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1116 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1117 /* set mic-in to output, unmute it */
1118 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1119 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1120 { } /* end */
1121};
1122
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001123static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001124 { 2, alc880_threestack_ch2_init },
1125 { 6, alc880_threestack_ch6_init },
1126};
1127
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001128static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001129 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001130 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001131 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001132 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001133 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1134 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001135 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1136 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1138 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1139 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1140 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1141 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1142 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1143 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1144 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1145 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1146 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001148 {
1149 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1150 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001151 .info = alc_ch_mode_info,
1152 .get = alc_ch_mode_get,
1153 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001154 },
1155 { } /* end */
1156};
1157
1158/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001159static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001160 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1161 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1162 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1163 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1164 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1165 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1166 {
1167 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1168 /* The multiple "Capture Source" controls confuse alsamixer
1169 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001170 */
1171 /* .name = "Capture Source", */
1172 .name = "Input Source",
1173 .count = 3,
1174 .info = alc_mux_enum_info,
1175 .get = alc_mux_enum_get,
1176 .put = alc_mux_enum_put,
1177 },
1178 { } /* end */
1179};
1180
1181/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001182static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001183 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1184 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1185 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1186 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 {
1188 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1189 /* The multiple "Capture Source" controls confuse alsamixer
1190 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 */
1192 /* .name = "Capture Source", */
1193 .name = "Input Source",
1194 .count = 2,
1195 .info = alc_mux_enum_info,
1196 .get = alc_mux_enum_get,
1197 .put = alc_mux_enum_put,
1198 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 { } /* end */
1200};
1201
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001202
1203
1204/*
1205 * ALC880 5-stack model
1206 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001207 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1208 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001209 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1210 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1211 */
1212
1213/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001214static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001215 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001216 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 { } /* end */
1218};
1219
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001220/* channel source setting (6/8 channel selection for 5-stack) */
1221/* 6ch mode */
1222static struct hda_verb alc880_fivestack_ch6_init[] = {
1223 /* set line-in to input, mute it */
1224 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1225 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001226 { } /* end */
1227};
1228
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001229/* 8ch mode */
1230static struct hda_verb alc880_fivestack_ch8_init[] = {
1231 /* set line-in to output, unmute it */
1232 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1233 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1234 { } /* end */
1235};
1236
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001237static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001238 { 6, alc880_fivestack_ch6_init },
1239 { 8, alc880_fivestack_ch8_init },
1240};
1241
1242
1243/*
1244 * ALC880 6-stack model
1245 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001246 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1247 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001248 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1249 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1250 */
1251
1252static hda_nid_t alc880_6st_dac_nids[4] = {
1253 /* front, rear, clfe, rear_surr */
1254 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001255};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001256
1257static struct hda_input_mux alc880_6stack_capture_source = {
1258 .num_items = 4,
1259 .items = {
1260 { "Mic", 0x0 },
1261 { "Front Mic", 0x1 },
1262 { "Line", 0x2 },
1263 { "CD", 0x4 },
1264 },
1265};
1266
1267/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001268static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001269 { 8, NULL },
1270};
1271
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001272static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001273 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001274 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001275 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001276 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001277 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1278 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001279 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1280 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001281 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001282 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001283 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1284 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1285 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1286 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1288 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1289 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1290 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1291 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1292 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001293 {
1294 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1295 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001296 .info = alc_ch_mode_info,
1297 .get = alc_ch_mode_get,
1298 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001299 },
1300 { } /* end */
1301};
1302
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001303
1304/*
1305 * ALC880 W810 model
1306 *
1307 * W810 has rear IO for:
1308 * Front (DAC 02)
1309 * Surround (DAC 03)
1310 * Center/LFE (DAC 04)
1311 * Digital out (06)
1312 *
1313 * The system also has a pair of internal speakers, and a headphone jack.
1314 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001315 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001316 * There is a variable resistor to control the speaker or headphone
1317 * volume. This is a hardware-only device without a software API.
1318 *
1319 * Plugging headphones in will disable the internal speakers. This is
1320 * implemented in hardware, not via the driver using jack sense. In
1321 * a similar fashion, plugging into the rear socket marked "front" will
1322 * disable both the speakers and headphones.
1323 *
1324 * For input, there's a microphone jack, and an "audio in" jack.
1325 * These may not do anything useful with this driver yet, because I
1326 * haven't setup any initialization verbs for these yet...
1327 */
1328
1329static hda_nid_t alc880_w810_dac_nids[3] = {
1330 /* front, rear/surround, clfe */
1331 0x02, 0x03, 0x04
1332};
1333
1334/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001335static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001336 { 6, NULL }
1337};
1338
1339/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001340static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001341 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001342 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001343 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001344 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001345 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1346 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001347 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1348 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001349 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1350 { } /* end */
1351};
1352
1353
1354/*
1355 * Z710V model
1356 *
1357 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001358 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1359 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001360 */
1361
1362static hda_nid_t alc880_z71v_dac_nids[1] = {
1363 0x02
1364};
1365#define ALC880_Z71V_HP_DAC 0x03
1366
1367/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001368static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001369 { 2, NULL }
1370};
1371
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001372static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001373 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001374 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001375 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001376 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001377 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1378 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1379 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1380 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1381 { } /* end */
1382};
1383
1384
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001385/*
1386 * ALC880 F1734 model
1387 *
1388 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1389 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1390 */
1391
1392static hda_nid_t alc880_f1734_dac_nids[1] = {
1393 0x03
1394};
1395#define ALC880_F1734_HP_DAC 0x02
1396
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001397static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001398 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001399 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001400 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1401 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001402 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1403 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001404 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1405 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001406 { } /* end */
1407};
1408
Takashi Iwai937b4162008-02-11 14:52:36 +01001409static struct hda_input_mux alc880_f1734_capture_source = {
1410 .num_items = 2,
1411 .items = {
1412 { "Mic", 0x1 },
1413 { "CD", 0x4 },
1414 },
1415};
1416
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001417
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001418/*
1419 * ALC880 ASUS model
1420 *
1421 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1422 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1423 * Mic = 0x18, Line = 0x1a
1424 */
1425
1426#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1427#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1428
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001429static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001430 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001431 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001432 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001433 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001434 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1435 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001436 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1437 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001438 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1439 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1440 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1441 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1442 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1443 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001444 {
1445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1446 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001447 .info = alc_ch_mode_info,
1448 .get = alc_ch_mode_get,
1449 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001450 },
1451 { } /* end */
1452};
1453
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001454/*
1455 * ALC880 ASUS W1V model
1456 *
1457 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1458 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1459 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1460 */
1461
1462/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001463static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001464 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1465 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001466 { } /* end */
1467};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001468
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001469/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001470static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001471 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1472 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1473 { } /* end */
1474};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001475
Kailang Yangdf694da2005-12-05 19:42:22 +01001476/* TCL S700 */
1477static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1478 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1479 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1480 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1481 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1482 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1483 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1484 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1485 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1486 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1487 {
1488 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1489 /* The multiple "Capture Source" controls confuse alsamixer
1490 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001491 */
1492 /* .name = "Capture Source", */
1493 .name = "Input Source",
1494 .count = 1,
1495 .info = alc_mux_enum_info,
1496 .get = alc_mux_enum_get,
1497 .put = alc_mux_enum_put,
1498 },
1499 { } /* end */
1500};
1501
Kailang Yangccc656c2006-10-17 12:32:26 +02001502/* Uniwill */
1503static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001504 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1505 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1506 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1507 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001508 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1510 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1511 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1512 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1513 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1514 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1515 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1516 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1517 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1518 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1519 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1520 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1521 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1522 {
1523 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1524 .name = "Channel Mode",
1525 .info = alc_ch_mode_info,
1526 .get = alc_ch_mode_get,
1527 .put = alc_ch_mode_put,
1528 },
1529 { } /* end */
1530};
1531
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001532static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1533 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1534 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1535 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1536 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1537 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1538 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1539 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1540 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1541 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1542 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1543 { } /* end */
1544};
1545
Kailang Yangccc656c2006-10-17 12:32:26 +02001546static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001547 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1548 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1549 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1550 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001551 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1552 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1553 { } /* end */
1554};
1555
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001557 * virtual master controls
1558 */
1559
1560/*
1561 * slave controls for virtual master
1562 */
1563static const char *alc_slave_vols[] = {
1564 "Front Playback Volume",
1565 "Surround Playback Volume",
1566 "Center Playback Volume",
1567 "LFE Playback Volume",
1568 "Side Playback Volume",
1569 "Headphone Playback Volume",
1570 "Speaker Playback Volume",
1571 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001572 "Line-Out Playback Volume",
1573 NULL,
1574};
1575
1576static const char *alc_slave_sws[] = {
1577 "Front Playback Switch",
1578 "Surround Playback Switch",
1579 "Center Playback Switch",
1580 "LFE Playback Switch",
1581 "Side Playback Switch",
1582 "Headphone Playback Switch",
1583 "Speaker Playback Switch",
1584 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001585 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001586 NULL,
1587};
1588
1589/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001590 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 */
1592static int alc_build_controls(struct hda_codec *codec)
1593{
1594 struct alc_spec *spec = codec->spec;
1595 int err;
1596 int i;
1597
1598 for (i = 0; i < spec->num_mixers; i++) {
1599 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1600 if (err < 0)
1601 return err;
1602 }
1603
1604 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001605 err = snd_hda_create_spdif_out_ctls(codec,
1606 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 if (err < 0)
1608 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001609 err = snd_hda_create_spdif_share_sw(codec,
1610 &spec->multiout);
1611 if (err < 0)
1612 return err;
1613 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 }
1615 if (spec->dig_in_nid) {
1616 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1617 if (err < 0)
1618 return err;
1619 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001620
1621 /* if we have no master control, let's create it */
1622 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001623 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001624 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001625 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001626 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001627 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001628 if (err < 0)
1629 return err;
1630 }
1631 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1632 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1633 NULL, alc_slave_sws);
1634 if (err < 0)
1635 return err;
1636 }
1637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 return 0;
1639}
1640
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642/*
1643 * initialize the codec volumes, etc
1644 */
1645
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001646/*
1647 * generic initialization of ADC, input mixers and output mixers
1648 */
1649static struct hda_verb alc880_volume_init_verbs[] = {
1650 /*
1651 * Unmute ADC0-2 and set the default input to mic-in
1652 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001653 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001654 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001655 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001656 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001657 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001658 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001660 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1661 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001662 * Note: PASD motherboards uses the Line In 2 as the input for front
1663 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001665 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001666 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1667 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1668 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1669 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1670 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1671 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1672 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001674 /*
1675 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001677 /* set vol=0 to output mixers */
1678 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1679 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1680 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1681 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1682 /* set up input amps for analog loopback */
1683 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1685 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001686 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1687 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001688 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1689 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001690 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1691 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 { }
1694};
1695
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001696/*
1697 * 3-stack pin configuration:
1698 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1699 */
1700static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1701 /*
1702 * preset connection lists of input pins
1703 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1704 */
1705 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1706 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1707 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1708
1709 /*
1710 * Set pin mode and muting
1711 */
1712 /* set front pin widgets 0x14 for output */
1713 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1714 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1715 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1716 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1717 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1718 /* Mic2 (as headphone out) for HP output */
1719 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1720 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1721 /* Line In pin widget for input */
1722 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1723 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1724 /* Line2 (as front mic) pin widget for input and vref at 80% */
1725 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1726 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1727 /* CD pin widget for input */
1728 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1729
1730 { }
1731};
1732
1733/*
1734 * 5-stack pin configuration:
1735 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1736 * line-in/side = 0x1a, f-mic = 0x1b
1737 */
1738static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1739 /*
1740 * preset connection lists of input pins
1741 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1742 */
1743 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1744 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1745
1746 /*
1747 * Set pin mode and muting
1748 */
1749 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001750 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1751 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1752 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1753 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001754 /* unmute pins for output (no gain on this amp) */
1755 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1756 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1757 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1758 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1759
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001761 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001762 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1763 /* Mic2 (as headphone out) for HP output */
1764 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001765 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001766 /* Line In pin widget for input */
1767 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1768 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1769 /* Line2 (as front mic) pin widget for input and vref at 80% */
1770 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1771 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1772 /* CD pin widget for input */
1773 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
1775 { }
1776};
1777
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001778/*
1779 * W810 pin configuration:
1780 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1781 */
1782static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* hphone/speaker input selector: front DAC */
1784 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1785
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001786 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1787 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1788 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1789 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1790 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1791 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1792
1793 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001794 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 { }
1797};
1798
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001799/*
1800 * Z71V pin configuration:
1801 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1802 */
1803static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001804 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001805 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001806 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001807 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001808
Takashi Iwai16ded522005-06-10 19:58:24 +02001809 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001810 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001811 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001812 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001813
1814 { }
1815};
1816
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001817/*
1818 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001819 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1820 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001821 */
1822static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1823 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1824
Takashi Iwai16ded522005-06-10 19:58:24 +02001825 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001826 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001827 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001828 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001829 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001831 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001832 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1833
Takashi Iwai16ded522005-06-10 19:58:24 +02001834 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001835 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001836 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001837 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001838 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001839 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001840 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001841 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001842 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02001843
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001844 { }
1845};
Takashi Iwai16ded522005-06-10 19:58:24 +02001846
Kailang Yangccc656c2006-10-17 12:32:26 +02001847/*
1848 * Uniwill pin configuration:
1849 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1850 * line = 0x1a
1851 */
1852static struct hda_verb alc880_uniwill_init_verbs[] = {
1853 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1854
1855 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1856 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1857 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1858 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1859 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1860 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1861 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1862 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1863 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1864 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1865 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1866 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1867 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1868 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1869
1870 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1871 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1872 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1873 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1874 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1875 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1876 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1877 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1878 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1879
1880 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1881 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1882
1883 { }
1884};
1885
1886/*
1887* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02001888* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02001889 */
1890static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1891 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1892
1893 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1894 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1895 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1896 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1897 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1898 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1899 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1900 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1901 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1902 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1903 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1904 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1905
1906 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1907 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1908 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1909 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1910 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1911 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1912
1913 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1914 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1915
1916 { }
1917};
1918
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001919static struct hda_verb alc880_beep_init_verbs[] = {
1920 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1921 { }
1922};
1923
Kailang Yangccc656c2006-10-17 12:32:26 +02001924/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001925static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001926{
1927 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001928 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001929
1930 present = snd_hda_codec_read(codec, 0x14, 0,
1931 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001932 bits = present ? HDA_AMP_MUTE : 0;
1933 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1934 HDA_AMP_MUTE, bits);
1935 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1936 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001937}
1938
1939/* auto-toggle front mic */
1940static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1941{
1942 unsigned int present;
1943 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001944
1945 present = snd_hda_codec_read(codec, 0x18, 0,
1946 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001947 bits = present ? HDA_AMP_MUTE : 0;
1948 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001949}
1950
1951static void alc880_uniwill_automute(struct hda_codec *codec)
1952{
1953 alc880_uniwill_hp_automute(codec);
1954 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001955}
1956
1957static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1958 unsigned int res)
1959{
1960 /* Looks like the unsol event is incompatible with the standard
1961 * definition. 4bit tag is placed at 28 bit!
1962 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001963 switch (res >> 28) {
1964 case ALC880_HP_EVENT:
1965 alc880_uniwill_hp_automute(codec);
1966 break;
1967 case ALC880_MIC_EVENT:
1968 alc880_uniwill_mic_automute(codec);
1969 break;
1970 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001971}
1972
1973static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1974{
1975 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001976 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001977
1978 present = snd_hda_codec_read(codec, 0x14, 0,
1979 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001980 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02001981 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001982}
1983
1984static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1985{
1986 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02001987
Kailang Yangccc656c2006-10-17 12:32:26 +02001988 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001989 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1990 present &= HDA_AMP_VOLMASK;
1991 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1992 HDA_AMP_VOLMASK, present);
1993 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1994 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001995}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001996
Kailang Yangccc656c2006-10-17 12:32:26 +02001997static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1998 unsigned int res)
1999{
2000 /* Looks like the unsol event is incompatible with the standard
2001 * definition. 4bit tag is placed at 28 bit!
2002 */
2003 if ((res >> 28) == ALC880_HP_EVENT)
2004 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002005 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002006 alc880_uniwill_p53_dcvol_automute(codec);
2007}
2008
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002009/*
2010 * F1734 pin configuration:
2011 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2012 */
2013static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002014 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002015 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2016 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2017 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2018 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2019
2020 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2021 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2022 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2023 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2024
2025 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2026 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002027 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002028 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2029 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2030 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2031 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2032 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2033 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002034
Takashi Iwai937b4162008-02-11 14:52:36 +01002035 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2036 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2037
Takashi Iwai16ded522005-06-10 19:58:24 +02002038 { }
2039};
2040
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002041/*
2042 * ASUS pin configuration:
2043 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2044 */
2045static struct hda_verb alc880_pin_asus_init_verbs[] = {
2046 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2047 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2048 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2049 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2050
2051 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2052 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2053 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2054 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2055 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2056 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2057 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2058 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2059
2060 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2061 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2062 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2064 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2065 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2066 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2067 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2068 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002069
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002070 { }
2071};
2072
2073/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002074#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2075#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002076
Kailang Yangdf694da2005-12-05 19:42:22 +01002077/* Clevo m520g init */
2078static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2079 /* headphone output */
2080 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2081 /* line-out */
2082 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2083 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2084 /* Line-in */
2085 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2086 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2087 /* CD */
2088 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2089 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2090 /* Mic1 (rear panel) */
2091 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2092 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2093 /* Mic2 (front panel) */
2094 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2095 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2096 /* headphone */
2097 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2098 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2099 /* change to EAPD mode */
2100 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2101 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2102
2103 { }
2104};
2105
2106static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002107 /* change to EAPD mode */
2108 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2109 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2110
Kailang Yangdf694da2005-12-05 19:42:22 +01002111 /* Headphone output */
2112 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2113 /* Front output*/
2114 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2115 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2116
2117 /* Line In pin widget for input */
2118 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2119 /* CD pin widget for input */
2120 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2121 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2122 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2123
2124 /* change to EAPD mode */
2125 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2126 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2127
2128 { }
2129};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002130
2131/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002132 * LG m1 express dual
2133 *
2134 * Pin assignment:
2135 * Rear Line-In/Out (blue): 0x14
2136 * Build-in Mic-In: 0x15
2137 * Speaker-out: 0x17
2138 * HP-Out (green): 0x1b
2139 * Mic-In/Out (red): 0x19
2140 * SPDIF-Out: 0x1e
2141 */
2142
2143/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2144static hda_nid_t alc880_lg_dac_nids[3] = {
2145 0x05, 0x02, 0x03
2146};
2147
2148/* seems analog CD is not working */
2149static struct hda_input_mux alc880_lg_capture_source = {
2150 .num_items = 3,
2151 .items = {
2152 { "Mic", 0x1 },
2153 { "Line", 0x5 },
2154 { "Internal Mic", 0x6 },
2155 },
2156};
2157
2158/* 2,4,6 channel modes */
2159static struct hda_verb alc880_lg_ch2_init[] = {
2160 /* set line-in and mic-in to input */
2161 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2162 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2163 { }
2164};
2165
2166static struct hda_verb alc880_lg_ch4_init[] = {
2167 /* set line-in to out and mic-in to input */
2168 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2169 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2170 { }
2171};
2172
2173static struct hda_verb alc880_lg_ch6_init[] = {
2174 /* set line-in and mic-in to output */
2175 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2176 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2177 { }
2178};
2179
2180static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2181 { 2, alc880_lg_ch2_init },
2182 { 4, alc880_lg_ch4_init },
2183 { 6, alc880_lg_ch6_init },
2184};
2185
2186static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002187 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2188 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002189 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2190 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2191 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2192 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2193 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2194 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2195 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2196 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2197 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2198 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2199 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2200 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2201 {
2202 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2203 .name = "Channel Mode",
2204 .info = alc_ch_mode_info,
2205 .get = alc_ch_mode_get,
2206 .put = alc_ch_mode_put,
2207 },
2208 { } /* end */
2209};
2210
2211static struct hda_verb alc880_lg_init_verbs[] = {
2212 /* set capture source to mic-in */
2213 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2214 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2215 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2216 /* mute all amp mixer inputs */
2217 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002218 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2219 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002220 /* line-in to input */
2221 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2222 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2223 /* built-in mic */
2224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2226 /* speaker-out */
2227 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2228 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2229 /* mic-in to input */
2230 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2231 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2232 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2233 /* HP-out */
2234 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2235 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2236 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2237 /* jack sense */
2238 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2239 { }
2240};
2241
2242/* toggle speaker-output according to the hp-jack state */
2243static void alc880_lg_automute(struct hda_codec *codec)
2244{
2245 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002246 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002247
2248 present = snd_hda_codec_read(codec, 0x1b, 0,
2249 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002250 bits = present ? HDA_AMP_MUTE : 0;
2251 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2252 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002253}
2254
2255static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2256{
2257 /* Looks like the unsol event is incompatible with the standard
2258 * definition. 4bit tag is placed at 28 bit!
2259 */
2260 if ((res >> 28) == 0x01)
2261 alc880_lg_automute(codec);
2262}
2263
2264/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002265 * LG LW20
2266 *
2267 * Pin assignment:
2268 * Speaker-out: 0x14
2269 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002270 * Built-in Mic-In: 0x19
2271 * Line-In: 0x1b
2272 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002273 * SPDIF-Out: 0x1e
2274 */
2275
Takashi Iwaid6815182006-03-23 16:06:23 +01002276static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002277 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002278 .items = {
2279 { "Mic", 0x0 },
2280 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002281 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002282 },
2283};
2284
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002285#define alc880_lg_lw_modes alc880_threestack_modes
2286
Takashi Iwaid6815182006-03-23 16:06:23 +01002287static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2289 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2290 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2291 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2292 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2293 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2294 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2295 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2296 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2297 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002298 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2299 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2300 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2301 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002302 {
2303 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2304 .name = "Channel Mode",
2305 .info = alc_ch_mode_info,
2306 .get = alc_ch_mode_get,
2307 .put = alc_ch_mode_put,
2308 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002309 { } /* end */
2310};
2311
2312static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002313 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2314 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2315 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2316
Takashi Iwaid6815182006-03-23 16:06:23 +01002317 /* set capture source to mic-in */
2318 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2319 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2320 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002321 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002322 /* speaker-out */
2323 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2324 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2325 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002326 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2327 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2328 /* mic-in to input */
2329 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2330 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2331 /* built-in mic */
2332 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2333 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2334 /* jack sense */
2335 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2336 { }
2337};
2338
2339/* toggle speaker-output according to the hp-jack state */
2340static void alc880_lg_lw_automute(struct hda_codec *codec)
2341{
2342 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002343 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002344
2345 present = snd_hda_codec_read(codec, 0x1b, 0,
2346 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002347 bits = present ? HDA_AMP_MUTE : 0;
2348 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2349 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002350}
2351
2352static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2353{
2354 /* Looks like the unsol event is incompatible with the standard
2355 * definition. 4bit tag is placed at 28 bit!
2356 */
2357 if ((res >> 28) == 0x01)
2358 alc880_lg_lw_automute(codec);
2359}
2360
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002361static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2362 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2363 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2364 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2365 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2366 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2367 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2368 { } /* end */
2369};
2370
2371static struct hda_input_mux alc880_medion_rim_capture_source = {
2372 .num_items = 2,
2373 .items = {
2374 { "Mic", 0x0 },
2375 { "Internal Mic", 0x1 },
2376 },
2377};
2378
2379static struct hda_verb alc880_medion_rim_init_verbs[] = {
2380 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2381
2382 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2383 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2384
2385 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2386 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2387 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2388 /* Mic2 (as headphone out) for HP output */
2389 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2390 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2391 /* Internal Speaker */
2392 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2393 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2394
2395 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2396 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2397
2398 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2399 { }
2400};
2401
2402/* toggle speaker-output according to the hp-jack state */
2403static void alc880_medion_rim_automute(struct hda_codec *codec)
2404{
2405 unsigned int present;
2406 unsigned char bits;
2407
2408 present = snd_hda_codec_read(codec, 0x14, 0,
2409 AC_VERB_GET_PIN_SENSE, 0)
2410 & AC_PINSENSE_PRESENCE;
2411 bits = present ? HDA_AMP_MUTE : 0;
2412 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2413 HDA_AMP_MUTE, bits);
2414 if (present)
2415 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2416 else
2417 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2418}
2419
2420static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2421 unsigned int res)
2422{
2423 /* Looks like the unsol event is incompatible with the standard
2424 * definition. 4bit tag is placed at 28 bit!
2425 */
2426 if ((res >> 28) == ALC880_HP_EVENT)
2427 alc880_medion_rim_automute(codec);
2428}
2429
Takashi Iwaicb53c622007-08-10 17:21:45 +02002430#ifdef CONFIG_SND_HDA_POWER_SAVE
2431static struct hda_amp_list alc880_loopbacks[] = {
2432 { 0x0b, HDA_INPUT, 0 },
2433 { 0x0b, HDA_INPUT, 1 },
2434 { 0x0b, HDA_INPUT, 2 },
2435 { 0x0b, HDA_INPUT, 3 },
2436 { 0x0b, HDA_INPUT, 4 },
2437 { } /* end */
2438};
2439
2440static struct hda_amp_list alc880_lg_loopbacks[] = {
2441 { 0x0b, HDA_INPUT, 1 },
2442 { 0x0b, HDA_INPUT, 6 },
2443 { 0x0b, HDA_INPUT, 7 },
2444 { } /* end */
2445};
2446#endif
2447
Takashi Iwaid6815182006-03-23 16:06:23 +01002448/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002449 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002450 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002451
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452static int alc_init(struct hda_codec *codec)
2453{
2454 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002455 unsigned int i;
2456
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002457 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002458 if (codec->vendor_id == 0x10ec0888)
2459 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002460
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002461 for (i = 0; i < spec->num_init_verbs; i++)
2462 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002463
2464 if (spec->init_hook)
2465 spec->init_hook(codec);
2466
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 return 0;
2468}
2469
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002470static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2471{
2472 struct alc_spec *spec = codec->spec;
2473
2474 if (spec->unsol_event)
2475 spec->unsol_event(codec, res);
2476}
2477
Takashi Iwaicb53c622007-08-10 17:21:45 +02002478#ifdef CONFIG_SND_HDA_POWER_SAVE
2479static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2480{
2481 struct alc_spec *spec = codec->spec;
2482 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2483}
2484#endif
2485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486/*
2487 * Analog playback callbacks
2488 */
2489static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2490 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002491 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492{
2493 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002494 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2495 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496}
2497
2498static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2499 struct hda_codec *codec,
2500 unsigned int stream_tag,
2501 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002502 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503{
2504 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002505 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2506 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507}
2508
2509static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2510 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002511 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512{
2513 struct alc_spec *spec = codec->spec;
2514 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2515}
2516
2517/*
2518 * Digital out
2519 */
2520static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2521 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002522 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
2524 struct alc_spec *spec = codec->spec;
2525 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2526}
2527
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002528static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2529 struct hda_codec *codec,
2530 unsigned int stream_tag,
2531 unsigned int format,
2532 struct snd_pcm_substream *substream)
2533{
2534 struct alc_spec *spec = codec->spec;
2535 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2536 stream_tag, format, substream);
2537}
2538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2540 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002541 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542{
2543 struct alc_spec *spec = codec->spec;
2544 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2545}
2546
2547/*
2548 * Analog capture
2549 */
Takashi Iwai63300792008-01-24 15:31:36 +01002550static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 struct hda_codec *codec,
2552 unsigned int stream_tag,
2553 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002554 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555{
2556 struct alc_spec *spec = codec->spec;
2557
Takashi Iwai63300792008-01-24 15:31:36 +01002558 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 stream_tag, 0, format);
2560 return 0;
2561}
2562
Takashi Iwai63300792008-01-24 15:31:36 +01002563static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002565 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566{
2567 struct alc_spec *spec = codec->spec;
2568
Takashi Iwai888afa12008-03-18 09:57:50 +01002569 snd_hda_codec_cleanup_stream(codec,
2570 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 return 0;
2572}
2573
2574
2575/*
2576 */
2577static struct hda_pcm_stream alc880_pcm_analog_playback = {
2578 .substreams = 1,
2579 .channels_min = 2,
2580 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002581 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 .ops = {
2583 .open = alc880_playback_pcm_open,
2584 .prepare = alc880_playback_pcm_prepare,
2585 .cleanup = alc880_playback_pcm_cleanup
2586 },
2587};
2588
2589static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002590 .substreams = 1,
2591 .channels_min = 2,
2592 .channels_max = 2,
2593 /* NID is set in alc_build_pcms */
2594};
2595
2596static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2597 .substreams = 1,
2598 .channels_min = 2,
2599 .channels_max = 2,
2600 /* NID is set in alc_build_pcms */
2601};
2602
2603static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2604 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 .channels_min = 2,
2606 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002607 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002609 .prepare = alc880_alt_capture_pcm_prepare,
2610 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 },
2612};
2613
2614static struct hda_pcm_stream alc880_pcm_digital_playback = {
2615 .substreams = 1,
2616 .channels_min = 2,
2617 .channels_max = 2,
2618 /* NID is set in alc_build_pcms */
2619 .ops = {
2620 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002621 .close = alc880_dig_playback_pcm_close,
2622 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 },
2624};
2625
2626static struct hda_pcm_stream alc880_pcm_digital_capture = {
2627 .substreams = 1,
2628 .channels_min = 2,
2629 .channels_max = 2,
2630 /* NID is set in alc_build_pcms */
2631};
2632
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002633/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002634static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002635 .substreams = 0,
2636 .channels_min = 0,
2637 .channels_max = 0,
2638};
2639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640static int alc_build_pcms(struct hda_codec *codec)
2641{
2642 struct alc_spec *spec = codec->spec;
2643 struct hda_pcm *info = spec->pcm_rec;
2644 int i;
2645
2646 codec->num_pcms = 1;
2647 codec->pcm_info = info;
2648
2649 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002650 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002651 if (snd_BUG_ON(!spec->multiout.dac_nids))
2652 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002653 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2654 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2655 }
2656 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002657 if (snd_BUG_ON(!spec->adc_nids))
2658 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002659 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2660 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Takashi Iwai4a471b72005-12-07 13:56:29 +01002663 if (spec->channel_mode) {
2664 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2665 for (i = 0; i < spec->num_channel_mode; i++) {
2666 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2667 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 }
2670 }
2671
Takashi Iwaie08a0072006-09-07 17:52:14 +02002672 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002674 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002675 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002677 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002678 if (spec->multiout.dig_out_nid &&
2679 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2681 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2682 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002683 if (spec->dig_in_nid &&
2684 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2686 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2687 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002688 /* FIXME: do we need this for all Realtek codec models? */
2689 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 }
2691
Takashi Iwaie08a0072006-09-07 17:52:14 +02002692 /* If the use of more than one ADC is requested for the current
2693 * model, configure a second analog capture-only PCM.
2694 */
2695 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002696 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2697 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002698 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002699 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002700 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002701 if (spec->alt_dac_nid) {
2702 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2703 *spec->stream_analog_alt_playback;
2704 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2705 spec->alt_dac_nid;
2706 } else {
2707 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2708 alc_pcm_null_stream;
2709 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2710 }
2711 if (spec->num_adc_nids > 1) {
2712 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2713 *spec->stream_analog_alt_capture;
2714 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2715 spec->adc_nids[1];
2716 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2717 spec->num_adc_nids - 1;
2718 } else {
2719 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2720 alc_pcm_null_stream;
2721 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002722 }
2723 }
2724
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 return 0;
2726}
2727
2728static void alc_free(struct hda_codec *codec)
2729{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002730 struct alc_spec *spec = codec->spec;
2731 unsigned int i;
2732
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002733 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002734 return;
2735
2736 if (spec->kctl_alloc) {
2737 for (i = 0; i < spec->num_kctl_used; i++)
2738 kfree(spec->kctl_alloc[i].name);
2739 kfree(spec->kctl_alloc);
2740 }
2741 kfree(spec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02002742 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743}
2744
2745/*
2746 */
2747static struct hda_codec_ops alc_patch_ops = {
2748 .build_controls = alc_build_controls,
2749 .build_pcms = alc_build_pcms,
2750 .init = alc_init,
2751 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002752 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002753#ifdef CONFIG_SND_HDA_POWER_SAVE
2754 .check_power_status = alc_check_power_status,
2755#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756};
2757
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002758
2759/*
2760 * Test configuration for debugging
2761 *
2762 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2763 * enum controls.
2764 */
2765#ifdef CONFIG_SND_DEBUG
2766static hda_nid_t alc880_test_dac_nids[4] = {
2767 0x02, 0x03, 0x04, 0x05
2768};
2769
2770static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002771 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002772 .items = {
2773 { "In-1", 0x0 },
2774 { "In-2", 0x1 },
2775 { "In-3", 0x2 },
2776 { "In-4", 0x3 },
2777 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002778 { "Front", 0x5 },
2779 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002780 },
2781};
2782
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002783static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002784 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002785 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002786 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002787 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002788};
2789
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002790static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2791 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002792{
2793 static char *texts[] = {
2794 "N/A", "Line Out", "HP Out",
2795 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2796 };
2797 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2798 uinfo->count = 1;
2799 uinfo->value.enumerated.items = 8;
2800 if (uinfo->value.enumerated.item >= 8)
2801 uinfo->value.enumerated.item = 7;
2802 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2803 return 0;
2804}
2805
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002806static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2807 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002808{
2809 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2810 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2811 unsigned int pin_ctl, item = 0;
2812
2813 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2814 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2815 if (pin_ctl & AC_PINCTL_OUT_EN) {
2816 if (pin_ctl & AC_PINCTL_HP_EN)
2817 item = 2;
2818 else
2819 item = 1;
2820 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2821 switch (pin_ctl & AC_PINCTL_VREFEN) {
2822 case AC_PINCTL_VREF_HIZ: item = 3; break;
2823 case AC_PINCTL_VREF_50: item = 4; break;
2824 case AC_PINCTL_VREF_GRD: item = 5; break;
2825 case AC_PINCTL_VREF_80: item = 6; break;
2826 case AC_PINCTL_VREF_100: item = 7; break;
2827 }
2828 }
2829 ucontrol->value.enumerated.item[0] = item;
2830 return 0;
2831}
2832
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002833static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2834 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002835{
2836 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2837 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2838 static unsigned int ctls[] = {
2839 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2840 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2841 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2842 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2843 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2844 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2845 };
2846 unsigned int old_ctl, new_ctl;
2847
2848 old_ctl = snd_hda_codec_read(codec, nid, 0,
2849 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2850 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2851 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002852 int val;
2853 snd_hda_codec_write_cache(codec, nid, 0,
2854 AC_VERB_SET_PIN_WIDGET_CONTROL,
2855 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002856 val = ucontrol->value.enumerated.item[0] >= 3 ?
2857 HDA_AMP_MUTE : 0;
2858 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2859 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002860 return 1;
2861 }
2862 return 0;
2863}
2864
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002865static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2866 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002867{
2868 static char *texts[] = {
2869 "Front", "Surround", "CLFE", "Side"
2870 };
2871 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2872 uinfo->count = 1;
2873 uinfo->value.enumerated.items = 4;
2874 if (uinfo->value.enumerated.item >= 4)
2875 uinfo->value.enumerated.item = 3;
2876 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2877 return 0;
2878}
2879
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002880static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2881 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002882{
2883 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2884 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2885 unsigned int sel;
2886
2887 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2888 ucontrol->value.enumerated.item[0] = sel & 3;
2889 return 0;
2890}
2891
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002892static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2893 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002894{
2895 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2896 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2897 unsigned int sel;
2898
2899 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2900 if (ucontrol->value.enumerated.item[0] != sel) {
2901 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002902 snd_hda_codec_write_cache(codec, nid, 0,
2903 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002904 return 1;
2905 }
2906 return 0;
2907}
2908
2909#define PIN_CTL_TEST(xname,nid) { \
2910 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2911 .name = xname, \
2912 .info = alc_test_pin_ctl_info, \
2913 .get = alc_test_pin_ctl_get, \
2914 .put = alc_test_pin_ctl_put, \
2915 .private_value = nid \
2916 }
2917
2918#define PIN_SRC_TEST(xname,nid) { \
2919 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2920 .name = xname, \
2921 .info = alc_test_pin_src_info, \
2922 .get = alc_test_pin_src_get, \
2923 .put = alc_test_pin_src_put, \
2924 .private_value = nid \
2925 }
2926
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002927static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002928 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2929 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2930 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2931 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002932 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2933 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2934 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2935 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002936 PIN_CTL_TEST("Front Pin Mode", 0x14),
2937 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2938 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2939 PIN_CTL_TEST("Side Pin Mode", 0x17),
2940 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2941 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2942 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2943 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2944 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2945 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2946 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2947 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2948 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2949 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2950 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2951 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2952 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2953 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2954 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2955 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2956 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2957 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002958 {
2959 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2960 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002961 .info = alc_ch_mode_info,
2962 .get = alc_ch_mode_get,
2963 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002964 },
2965 { } /* end */
2966};
2967
2968static struct hda_verb alc880_test_init_verbs[] = {
2969 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002970 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2971 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2972 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2973 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2974 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2975 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2976 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2977 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002978 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002979 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2980 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2981 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2982 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002983 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002984 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2985 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2986 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2987 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002988 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002989 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2990 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2991 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2992 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002993 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002994 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2995 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002996 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2997 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2998 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002999 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003000 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3001 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3002 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3003 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003004 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003005 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003006 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003007 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003008 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003009 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003010 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003011 /* Analog input/passthru */
3012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3014 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3015 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3016 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003017 { }
3018};
3019#endif
3020
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021/*
3022 */
3023
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003024static const char *alc880_models[ALC880_MODEL_LAST] = {
3025 [ALC880_3ST] = "3stack",
3026 [ALC880_TCL_S700] = "tcl",
3027 [ALC880_3ST_DIG] = "3stack-digout",
3028 [ALC880_CLEVO] = "clevo",
3029 [ALC880_5ST] = "5stack",
3030 [ALC880_5ST_DIG] = "5stack-digout",
3031 [ALC880_W810] = "w810",
3032 [ALC880_Z71V] = "z71v",
3033 [ALC880_6ST] = "6stack",
3034 [ALC880_6ST_DIG] = "6stack-digout",
3035 [ALC880_ASUS] = "asus",
3036 [ALC880_ASUS_W1V] = "asus-w1v",
3037 [ALC880_ASUS_DIG] = "asus-dig",
3038 [ALC880_ASUS_DIG2] = "asus-dig2",
3039 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003040 [ALC880_UNIWILL_P53] = "uniwill-p53",
3041 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003042 [ALC880_F1734] = "F1734",
3043 [ALC880_LG] = "lg",
3044 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003045 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003046#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003047 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003048#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003049 [ALC880_AUTO] = "auto",
3050};
3051
3052static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003053 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003054 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3055 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3056 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3057 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3058 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3059 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3060 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3061 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003062 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3063 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003064 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3065 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3066 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3067 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3068 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3069 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3070 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3071 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3072 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3073 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003074 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003075 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3076 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3077 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003078 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003079 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003080 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3081 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003082 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3083 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003084 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3085 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3086 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3087 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003088 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3089 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003090 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003091 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003092 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003093 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003094 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3095 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003096 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003097 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003098 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003099 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003100 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003101 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003102 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003103 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003104 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003105 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3106 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003107 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003108 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3109 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3110 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3111 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003112 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3113 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003114 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003115 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003116 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3117 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003118 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3119 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3120 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003121 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3122 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3123 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 {}
3125};
3126
Takashi Iwai16ded522005-06-10 19:58:24 +02003127/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003128 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003130static struct alc_config_preset alc880_presets[] = {
3131 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003132 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003133 .init_verbs = { alc880_volume_init_verbs,
3134 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003135 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003136 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003137 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3138 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003139 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003140 .input_mux = &alc880_capture_source,
3141 },
3142 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003143 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003144 .init_verbs = { alc880_volume_init_verbs,
3145 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003146 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003147 .dac_nids = alc880_dac_nids,
3148 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003149 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3150 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003151 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003152 .input_mux = &alc880_capture_source,
3153 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003154 [ALC880_TCL_S700] = {
3155 .mixers = { alc880_tcl_s700_mixer },
3156 .init_verbs = { alc880_volume_init_verbs,
3157 alc880_pin_tcl_S700_init_verbs,
3158 alc880_gpio2_init_verbs },
3159 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3160 .dac_nids = alc880_dac_nids,
3161 .hp_nid = 0x03,
3162 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3163 .channel_mode = alc880_2_jack_modes,
3164 .input_mux = &alc880_capture_source,
3165 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003166 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003167 .mixers = { alc880_three_stack_mixer,
3168 alc880_five_stack_mixer},
3169 .init_verbs = { alc880_volume_init_verbs,
3170 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003171 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3172 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003173 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3174 .channel_mode = alc880_fivestack_modes,
3175 .input_mux = &alc880_capture_source,
3176 },
3177 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003178 .mixers = { alc880_three_stack_mixer,
3179 alc880_five_stack_mixer },
3180 .init_verbs = { alc880_volume_init_verbs,
3181 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003182 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3183 .dac_nids = alc880_dac_nids,
3184 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003185 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3186 .channel_mode = alc880_fivestack_modes,
3187 .input_mux = &alc880_capture_source,
3188 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003189 [ALC880_6ST] = {
3190 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003191 .init_verbs = { alc880_volume_init_verbs,
3192 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003193 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3194 .dac_nids = alc880_6st_dac_nids,
3195 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3196 .channel_mode = alc880_sixstack_modes,
3197 .input_mux = &alc880_6stack_capture_source,
3198 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003199 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003200 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003201 .init_verbs = { alc880_volume_init_verbs,
3202 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003203 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3204 .dac_nids = alc880_6st_dac_nids,
3205 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003206 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3207 .channel_mode = alc880_sixstack_modes,
3208 .input_mux = &alc880_6stack_capture_source,
3209 },
3210 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003211 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003212 .init_verbs = { alc880_volume_init_verbs,
3213 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003214 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003215 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3216 .dac_nids = alc880_w810_dac_nids,
3217 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003218 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3219 .channel_mode = alc880_w810_modes,
3220 .input_mux = &alc880_capture_source,
3221 },
3222 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003223 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003224 .init_verbs = { alc880_volume_init_verbs,
3225 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003226 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3227 .dac_nids = alc880_z71v_dac_nids,
3228 .dig_out_nid = ALC880_DIGOUT_NID,
3229 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003230 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3231 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003232 .input_mux = &alc880_capture_source,
3233 },
3234 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003235 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003236 .init_verbs = { alc880_volume_init_verbs,
3237 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003238 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3239 .dac_nids = alc880_f1734_dac_nids,
3240 .hp_nid = 0x02,
3241 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3242 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003243 .input_mux = &alc880_f1734_capture_source,
3244 .unsol_event = alc880_uniwill_p53_unsol_event,
3245 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003246 },
3247 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003248 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003249 .init_verbs = { alc880_volume_init_verbs,
3250 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003251 alc880_gpio1_init_verbs },
3252 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3253 .dac_nids = alc880_asus_dac_nids,
3254 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3255 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003256 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003257 .input_mux = &alc880_capture_source,
3258 },
3259 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003260 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003261 .init_verbs = { alc880_volume_init_verbs,
3262 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003263 alc880_gpio1_init_verbs },
3264 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3265 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003266 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003267 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3268 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003269 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003270 .input_mux = &alc880_capture_source,
3271 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003272 [ALC880_ASUS_DIG2] = {
3273 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003274 .init_verbs = { alc880_volume_init_verbs,
3275 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003276 alc880_gpio2_init_verbs }, /* use GPIO2 */
3277 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3278 .dac_nids = alc880_asus_dac_nids,
3279 .dig_out_nid = ALC880_DIGOUT_NID,
3280 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3281 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003282 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003283 .input_mux = &alc880_capture_source,
3284 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003285 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003286 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003287 .init_verbs = { alc880_volume_init_verbs,
3288 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003289 alc880_gpio1_init_verbs },
3290 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3291 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003292 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003293 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3294 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003295 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003296 .input_mux = &alc880_capture_source,
3297 },
3298 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003299 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003300 .init_verbs = { alc880_volume_init_verbs,
3301 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003302 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3303 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003304 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003305 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3306 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003307 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003308 .input_mux = &alc880_capture_source,
3309 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003310 [ALC880_UNIWILL] = {
3311 .mixers = { alc880_uniwill_mixer },
3312 .init_verbs = { alc880_volume_init_verbs,
3313 alc880_uniwill_init_verbs },
3314 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3315 .dac_nids = alc880_asus_dac_nids,
3316 .dig_out_nid = ALC880_DIGOUT_NID,
3317 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3318 .channel_mode = alc880_threestack_modes,
3319 .need_dac_fix = 1,
3320 .input_mux = &alc880_capture_source,
3321 .unsol_event = alc880_uniwill_unsol_event,
3322 .init_hook = alc880_uniwill_automute,
3323 },
3324 [ALC880_UNIWILL_P53] = {
3325 .mixers = { alc880_uniwill_p53_mixer },
3326 .init_verbs = { alc880_volume_init_verbs,
3327 alc880_uniwill_p53_init_verbs },
3328 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3329 .dac_nids = alc880_asus_dac_nids,
3330 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003331 .channel_mode = alc880_threestack_modes,
3332 .input_mux = &alc880_capture_source,
3333 .unsol_event = alc880_uniwill_p53_unsol_event,
3334 .init_hook = alc880_uniwill_p53_hp_automute,
3335 },
3336 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003337 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003338 alc880_pcbeep_mixer, },
3339 .init_verbs = { alc880_volume_init_verbs,
3340 alc880_uniwill_p53_init_verbs,
3341 alc880_beep_init_verbs },
3342 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3343 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003344 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003345 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3346 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003347 .input_mux = &alc880_capture_source,
3348 .unsol_event = alc880_uniwill_p53_unsol_event,
3349 .init_hook = alc880_uniwill_p53_hp_automute,
3350 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003351 [ALC880_CLEVO] = {
3352 .mixers = { alc880_three_stack_mixer },
3353 .init_verbs = { alc880_volume_init_verbs,
3354 alc880_pin_clevo_init_verbs },
3355 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3356 .dac_nids = alc880_dac_nids,
3357 .hp_nid = 0x03,
3358 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3359 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003360 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003361 .input_mux = &alc880_capture_source,
3362 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003363 [ALC880_LG] = {
3364 .mixers = { alc880_lg_mixer },
3365 .init_verbs = { alc880_volume_init_verbs,
3366 alc880_lg_init_verbs },
3367 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3368 .dac_nids = alc880_lg_dac_nids,
3369 .dig_out_nid = ALC880_DIGOUT_NID,
3370 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3371 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003372 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003373 .input_mux = &alc880_lg_capture_source,
3374 .unsol_event = alc880_lg_unsol_event,
3375 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003376#ifdef CONFIG_SND_HDA_POWER_SAVE
3377 .loopbacks = alc880_lg_loopbacks,
3378#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003379 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003380 [ALC880_LG_LW] = {
3381 .mixers = { alc880_lg_lw_mixer },
3382 .init_verbs = { alc880_volume_init_verbs,
3383 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003384 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003385 .dac_nids = alc880_dac_nids,
3386 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003387 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3388 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003389 .input_mux = &alc880_lg_lw_capture_source,
3390 .unsol_event = alc880_lg_lw_unsol_event,
3391 .init_hook = alc880_lg_lw_automute,
3392 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003393 [ALC880_MEDION_RIM] = {
3394 .mixers = { alc880_medion_rim_mixer },
3395 .init_verbs = { alc880_volume_init_verbs,
3396 alc880_medion_rim_init_verbs,
3397 alc_gpio2_init_verbs },
3398 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3399 .dac_nids = alc880_dac_nids,
3400 .dig_out_nid = ALC880_DIGOUT_NID,
3401 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3402 .channel_mode = alc880_2_jack_modes,
3403 .input_mux = &alc880_medion_rim_capture_source,
3404 .unsol_event = alc880_medion_rim_unsol_event,
3405 .init_hook = alc880_medion_rim_automute,
3406 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003407#ifdef CONFIG_SND_DEBUG
3408 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003409 .mixers = { alc880_test_mixer },
3410 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003411 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3412 .dac_nids = alc880_test_dac_nids,
3413 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003414 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3415 .channel_mode = alc880_test_modes,
3416 .input_mux = &alc880_test_capture_source,
3417 },
3418#endif
3419};
3420
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003421/*
3422 * Automatic parse of I/O pins from the BIOS configuration
3423 */
3424
3425#define NUM_CONTROL_ALLOC 32
3426#define NUM_VERB_ALLOC 32
3427
3428enum {
3429 ALC_CTL_WIDGET_VOL,
3430 ALC_CTL_WIDGET_MUTE,
3431 ALC_CTL_BIND_MUTE,
3432};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003433static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003434 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3435 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003436 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003437};
3438
3439/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003440static int add_control(struct alc_spec *spec, int type, const char *name,
3441 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003442{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003443 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003444
3445 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3446 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3447
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003448 /* array + terminator */
3449 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3450 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003451 return -ENOMEM;
3452 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003453 memcpy(knew, spec->kctl_alloc,
3454 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003455 kfree(spec->kctl_alloc);
3456 }
3457 spec->kctl_alloc = knew;
3458 spec->num_kctl_alloc = num;
3459 }
3460
3461 knew = &spec->kctl_alloc[spec->num_kctl_used];
3462 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003463 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003464 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003465 return -ENOMEM;
3466 knew->private_value = val;
3467 spec->num_kctl_used++;
3468 return 0;
3469}
3470
3471#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3472#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3473#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3474#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3475#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3476#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3477#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3478#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3479#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3480#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3481#define ALC880_PIN_CD_NID 0x1c
3482
3483/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003484static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3485 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003486{
3487 hda_nid_t nid;
3488 int assigned[4];
3489 int i, j;
3490
3491 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003492 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003493
3494 /* check the pins hardwired to audio widget */
3495 for (i = 0; i < cfg->line_outs; i++) {
3496 nid = cfg->line_out_pins[i];
3497 if (alc880_is_fixed_pin(nid)) {
3498 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003499 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003500 assigned[idx] = 1;
3501 }
3502 }
3503 /* left pins can be connect to any audio widget */
3504 for (i = 0; i < cfg->line_outs; i++) {
3505 nid = cfg->line_out_pins[i];
3506 if (alc880_is_fixed_pin(nid))
3507 continue;
3508 /* search for an empty channel */
3509 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003510 if (!assigned[j]) {
3511 spec->multiout.dac_nids[i] =
3512 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003513 assigned[j] = 1;
3514 break;
3515 }
3516 }
3517 }
3518 spec->multiout.num_dacs = cfg->line_outs;
3519 return 0;
3520}
3521
3522/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003523static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3524 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003525{
3526 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003527 static const char *chname[4] = {
3528 "Front", "Surround", NULL /*CLFE*/, "Side"
3529 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003530 hda_nid_t nid;
3531 int i, err;
3532
3533 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003534 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003535 continue;
3536 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3537 if (i == 2) {
3538 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003539 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3540 "Center Playback Volume",
3541 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3542 HDA_OUTPUT));
3543 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003544 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003545 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3546 "LFE Playback Volume",
3547 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3548 HDA_OUTPUT));
3549 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003550 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003551 err = add_control(spec, ALC_CTL_BIND_MUTE,
3552 "Center Playback Switch",
3553 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3554 HDA_INPUT));
3555 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003556 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003557 err = add_control(spec, ALC_CTL_BIND_MUTE,
3558 "LFE Playback Switch",
3559 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3560 HDA_INPUT));
3561 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003562 return err;
3563 } else {
3564 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003565 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3566 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3567 HDA_OUTPUT));
3568 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003569 return err;
3570 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003571 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3572 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3573 HDA_INPUT));
3574 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003575 return err;
3576 }
3577 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003578 return 0;
3579}
3580
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003581/* add playback controls for speaker and HP outputs */
3582static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3583 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003584{
3585 hda_nid_t nid;
3586 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003587 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003588
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003589 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003590 return 0;
3591
3592 if (alc880_is_fixed_pin(pin)) {
3593 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003594 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003595 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003596 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003597 else
3598 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003599 /* control HP volume/switch on the output mixer amp */
3600 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003601 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003602 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3603 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3604 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003605 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003606 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003607 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3608 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3609 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003610 return err;
3611 } else if (alc880_is_multi_pin(pin)) {
3612 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003613 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003614 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003615 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3616 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3617 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003618 return err;
3619 }
3620 return 0;
3621}
3622
3623/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003624static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3625 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003626 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003627{
3628 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003629 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003630
3631 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003632 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3633 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3634 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003635 return err;
3636 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003637 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3638 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3639 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003640 return err;
3641 return 0;
3642}
3643
3644/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003645static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3646 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003647{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003648 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003649 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003650
3651 for (i = 0; i < AUTO_PIN_LAST; i++) {
3652 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003653 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003654 err = new_analog_input(spec, cfg->input_pins[i],
3655 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003656 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003657 if (err < 0)
3658 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003659 imux->items[imux->num_items].label =
3660 auto_pin_cfg_labels[i];
3661 imux->items[imux->num_items].index =
3662 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003663 imux->num_items++;
3664 }
3665 }
3666 return 0;
3667}
3668
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003669static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3670 unsigned int pin_type)
3671{
3672 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3673 pin_type);
3674 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003675 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3676 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003677}
3678
Kailang Yangdf694da2005-12-05 19:42:22 +01003679static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3680 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003681 int dac_idx)
3682{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003683 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003684 /* need the manual connection? */
3685 if (alc880_is_multi_pin(nid)) {
3686 struct alc_spec *spec = codec->spec;
3687 int idx = alc880_multi_pin_idx(nid);
3688 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3689 AC_VERB_SET_CONNECT_SEL,
3690 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3691 }
3692}
3693
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003694static int get_pin_type(int line_out_type)
3695{
3696 if (line_out_type == AUTO_PIN_HP_OUT)
3697 return PIN_HP;
3698 else
3699 return PIN_OUT;
3700}
3701
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003702static void alc880_auto_init_multi_out(struct hda_codec *codec)
3703{
3704 struct alc_spec *spec = codec->spec;
3705 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02003706
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003707 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003708 for (i = 0; i < spec->autocfg.line_outs; i++) {
3709 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003710 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3711 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003712 }
3713}
3714
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003715static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003716{
3717 struct alc_spec *spec = codec->spec;
3718 hda_nid_t pin;
3719
Takashi Iwai82bc9552006-03-21 11:24:42 +01003720 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003721 if (pin) /* connect to front */
3722 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003723 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003724 if (pin) /* connect to front */
3725 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3726}
3727
3728static void alc880_auto_init_analog_input(struct hda_codec *codec)
3729{
3730 struct alc_spec *spec = codec->spec;
3731 int i;
3732
3733 for (i = 0; i < AUTO_PIN_LAST; i++) {
3734 hda_nid_t nid = spec->autocfg.input_pins[i];
3735 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003736 snd_hda_codec_write(codec, nid, 0,
3737 AC_VERB_SET_PIN_WIDGET_CONTROL,
3738 i <= AUTO_PIN_FRONT_MIC ?
3739 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003740 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003741 snd_hda_codec_write(codec, nid, 0,
3742 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003743 AMP_OUT_MUTE);
3744 }
3745 }
3746}
3747
3748/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003749/* return 1 if successful, 0 if the proper config is not found,
3750 * or a negative error code
3751 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003752static int alc880_parse_auto_config(struct hda_codec *codec)
3753{
3754 struct alc_spec *spec = codec->spec;
3755 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003756 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003757
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003758 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3759 alc880_ignore);
3760 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003761 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003762 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003763 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003764
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003765 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3766 if (err < 0)
3767 return err;
3768 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3769 if (err < 0)
3770 return err;
3771 err = alc880_auto_create_extra_out(spec,
3772 spec->autocfg.speaker_pins[0],
3773 "Speaker");
3774 if (err < 0)
3775 return err;
3776 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3777 "Headphone");
3778 if (err < 0)
3779 return err;
3780 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3781 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003782 return err;
3783
3784 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3785
3786 if (spec->autocfg.dig_out_pin)
3787 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3788 if (spec->autocfg.dig_in_pin)
3789 spec->dig_in_nid = ALC880_DIGIN_NID;
3790
3791 if (spec->kctl_alloc)
3792 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3793
3794 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3795
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003796 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003797 spec->input_mux = &spec->private_imux;
3798
3799 return 1;
3800}
3801
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003802/* additional initialization for auto-configuration model */
3803static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003804{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003805 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003806 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003807 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003808 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003809 if (spec->unsol_event)
3810 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003811}
3812
3813/*
3814 * OK, here we have finally the patch for ALC880
3815 */
3816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817static int patch_alc880(struct hda_codec *codec)
3818{
3819 struct alc_spec *spec;
3820 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003821 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003823 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 if (spec == NULL)
3825 return -ENOMEM;
3826
3827 codec->spec = spec;
3828
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003829 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3830 alc880_models,
3831 alc880_cfg_tbl);
3832 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003833 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3834 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003835 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 }
3837
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003838 if (board_config == ALC880_AUTO) {
3839 /* automatic parse from the BIOS config */
3840 err = alc880_parse_auto_config(codec);
3841 if (err < 0) {
3842 alc_free(codec);
3843 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003844 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003845 printk(KERN_INFO
3846 "hda_codec: Cannot set up configuration "
3847 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003848 board_config = ALC880_3ST;
3849 }
3850 }
3851
Kailang Yangdf694da2005-12-05 19:42:22 +01003852 if (board_config != ALC880_AUTO)
3853 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854
3855 spec->stream_name_analog = "ALC880 Analog";
3856 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3857 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003858 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859
3860 spec->stream_name_digital = "ALC880 Digital";
3861 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3862 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3863
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003864 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003865 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003866 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003867 /* get type */
3868 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003869 if (wcap != AC_WID_AUD_IN) {
3870 spec->adc_nids = alc880_adc_nids_alt;
3871 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003872 spec->mixers[spec->num_mixers] =
3873 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003874 spec->num_mixers++;
3875 } else {
3876 spec->adc_nids = alc880_adc_nids;
3877 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3878 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3879 spec->num_mixers++;
3880 }
3881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
Takashi Iwai2134ea42008-01-10 16:53:55 +01003883 spec->vmaster_nid = 0x0c;
3884
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003886 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003887 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003888#ifdef CONFIG_SND_HDA_POWER_SAVE
3889 if (!spec->loopback.amplist)
3890 spec->loopback.amplist = alc880_loopbacks;
3891#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892
3893 return 0;
3894}
3895
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003896
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897/*
3898 * ALC260 support
3899 */
3900
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003901static hda_nid_t alc260_dac_nids[1] = {
3902 /* front */
3903 0x02,
3904};
3905
3906static hda_nid_t alc260_adc_nids[1] = {
3907 /* ADC0 */
3908 0x04,
3909};
3910
Kailang Yangdf694da2005-12-05 19:42:22 +01003911static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003912 /* ADC1 */
3913 0x05,
3914};
3915
Kailang Yangdf694da2005-12-05 19:42:22 +01003916static hda_nid_t alc260_hp_adc_nids[2] = {
3917 /* ADC1, 0 */
3918 0x05, 0x04
3919};
3920
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003921/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3922 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3923 */
3924static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003925 /* ADC0, ADC1 */
3926 0x04, 0x05
3927};
3928
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003929#define ALC260_DIGOUT_NID 0x03
3930#define ALC260_DIGIN_NID 0x06
3931
3932static struct hda_input_mux alc260_capture_source = {
3933 .num_items = 4,
3934 .items = {
3935 { "Mic", 0x0 },
3936 { "Front Mic", 0x1 },
3937 { "Line", 0x2 },
3938 { "CD", 0x4 },
3939 },
3940};
3941
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003942/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003943 * headphone jack and the internal CD lines since these are the only pins at
3944 * which audio can appear. For flexibility, also allow the option of
3945 * recording the mixer output on the second ADC (ADC0 doesn't have a
3946 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003947 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003948static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3949 {
3950 .num_items = 3,
3951 .items = {
3952 { "Mic/Line", 0x0 },
3953 { "CD", 0x4 },
3954 { "Headphone", 0x2 },
3955 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003956 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003957 {
3958 .num_items = 4,
3959 .items = {
3960 { "Mic/Line", 0x0 },
3961 { "CD", 0x4 },
3962 { "Headphone", 0x2 },
3963 { "Mixer", 0x5 },
3964 },
3965 },
3966
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003967};
3968
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003969/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3970 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003971 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003972static struct hda_input_mux alc260_acer_capture_sources[2] = {
3973 {
3974 .num_items = 4,
3975 .items = {
3976 { "Mic", 0x0 },
3977 { "Line", 0x2 },
3978 { "CD", 0x4 },
3979 { "Headphone", 0x5 },
3980 },
3981 },
3982 {
3983 .num_items = 5,
3984 .items = {
3985 { "Mic", 0x0 },
3986 { "Line", 0x2 },
3987 { "CD", 0x4 },
3988 { "Headphone", 0x6 },
3989 { "Mixer", 0x5 },
3990 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003991 },
3992};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993/*
3994 * This is just place-holder, so there's something for alc_build_pcms to look
3995 * at when it calculates the maximum number of channels. ALC260 has no mixer
3996 * element which allows changing the channel mode, so the verb list is
3997 * never used.
3998 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003999static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 { 2, NULL },
4001};
4002
Kailang Yangdf694da2005-12-05 19:42:22 +01004003
4004/* Mixer combinations
4005 *
4006 * basic: base_output + input + pc_beep + capture
4007 * HP: base_output + input + capture_alt
4008 * HP_3013: hp_3013 + input + capture
4009 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004010 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004011 */
4012
4013static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004014 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004015 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004016 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4017 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4018 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4019 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4020 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004021};
Kailang Yangdf694da2005-12-05 19:42:22 +01004022
4023static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4025 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4026 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4027 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4028 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4029 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4030 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4031 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 { } /* end */
4033};
4034
Kailang Yangdf694da2005-12-05 19:42:22 +01004035static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
4036 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
4037 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
4038 { } /* end */
4039};
4040
Takashi Iwaibec15c32008-01-28 18:16:30 +01004041/* update HP, line and mono out pins according to the master switch */
4042static void alc260_hp_master_update(struct hda_codec *codec,
4043 hda_nid_t hp, hda_nid_t line,
4044 hda_nid_t mono)
4045{
4046 struct alc_spec *spec = codec->spec;
4047 unsigned int val = spec->master_sw ? PIN_HP : 0;
4048 /* change HP and line-out pins */
4049 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4050 val);
4051 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4052 val);
4053 /* mono (speaker) depending on the HP jack sense */
4054 val = (val && !spec->jack_present) ? PIN_OUT : 0;
4055 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4056 val);
4057}
4058
4059static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4060 struct snd_ctl_elem_value *ucontrol)
4061{
4062 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4063 struct alc_spec *spec = codec->spec;
4064 *ucontrol->value.integer.value = spec->master_sw;
4065 return 0;
4066}
4067
4068static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4069 struct snd_ctl_elem_value *ucontrol)
4070{
4071 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4072 struct alc_spec *spec = codec->spec;
4073 int val = !!*ucontrol->value.integer.value;
4074 hda_nid_t hp, line, mono;
4075
4076 if (val == spec->master_sw)
4077 return 0;
4078 spec->master_sw = val;
4079 hp = (kcontrol->private_value >> 16) & 0xff;
4080 line = (kcontrol->private_value >> 8) & 0xff;
4081 mono = kcontrol->private_value & 0xff;
4082 alc260_hp_master_update(codec, hp, line, mono);
4083 return 1;
4084}
4085
4086static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4087 {
4088 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4089 .name = "Master Playback Switch",
4090 .info = snd_ctl_boolean_mono_info,
4091 .get = alc260_hp_master_sw_get,
4092 .put = alc260_hp_master_sw_put,
4093 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4094 },
4095 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4096 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4097 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4098 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4099 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4100 HDA_OUTPUT),
4101 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4102 { } /* end */
4103};
4104
4105static struct hda_verb alc260_hp_unsol_verbs[] = {
4106 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4107 {},
4108};
4109
4110static void alc260_hp_automute(struct hda_codec *codec)
4111{
4112 struct alc_spec *spec = codec->spec;
4113 unsigned int present;
4114
4115 present = snd_hda_codec_read(codec, 0x10, 0,
4116 AC_VERB_GET_PIN_SENSE, 0);
4117 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4118 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4119}
4120
4121static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4122{
4123 if ((res >> 26) == ALC880_HP_EVENT)
4124 alc260_hp_automute(codec);
4125}
4126
Kailang Yangdf694da2005-12-05 19:42:22 +01004127static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004128 {
4129 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4130 .name = "Master Playback Switch",
4131 .info = snd_ctl_boolean_mono_info,
4132 .get = alc260_hp_master_sw_get,
4133 .put = alc260_hp_master_sw_put,
4134 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
4135 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004136 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4137 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4138 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4139 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4140 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4141 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004142 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4143 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004144 { } /* end */
4145};
4146
Kailang Yang3f878302008-08-26 13:02:23 +02004147static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4148 .ops = &snd_hda_bind_vol,
4149 .values = {
4150 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4151 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4152 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4153 0
4154 },
4155};
4156
4157static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4158 .ops = &snd_hda_bind_sw,
4159 .values = {
4160 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4161 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4162 0
4163 },
4164};
4165
4166static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4167 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4168 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4169 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4170 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4171 { } /* end */
4172};
4173
Takashi Iwaibec15c32008-01-28 18:16:30 +01004174static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4175 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4176 {},
4177};
4178
4179static void alc260_hp_3013_automute(struct hda_codec *codec)
4180{
4181 struct alc_spec *spec = codec->spec;
4182 unsigned int present;
4183
4184 present = snd_hda_codec_read(codec, 0x15, 0,
4185 AC_VERB_GET_PIN_SENSE, 0);
4186 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4187 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
4188}
4189
4190static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4191 unsigned int res)
4192{
4193 if ((res >> 26) == ALC880_HP_EVENT)
4194 alc260_hp_3013_automute(codec);
4195}
4196
Kailang Yang3f878302008-08-26 13:02:23 +02004197static void alc260_hp_3012_automute(struct hda_codec *codec)
4198{
4199 unsigned int present, bits;
4200
4201 present = snd_hda_codec_read(codec, 0x10, 0,
4202 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4203
4204 bits = present ? 0 : PIN_OUT;
4205 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4206 bits);
4207 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4208 bits);
4209 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4210 bits);
4211}
4212
4213static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4214 unsigned int res)
4215{
4216 if ((res >> 26) == ALC880_HP_EVENT)
4217 alc260_hp_3012_automute(codec);
4218}
4219
4220/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004221 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4222 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004223static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004224 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004225 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004226 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004227 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4228 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4229 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4230 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004231 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004232 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4233 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004234 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4235 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004236 { } /* end */
4237};
4238
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004239/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4240 * versions of the ALC260 don't act on requests to enable mic bias from NID
4241 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4242 * datasheet doesn't mention this restriction. At this stage it's not clear
4243 * whether this behaviour is intentional or is a hardware bug in chip
4244 * revisions available in early 2006. Therefore for now allow the
4245 * "Headphone Jack Mode" control to span all choices, but if it turns out
4246 * that the lack of mic bias for this NID is intentional we could change the
4247 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4248 *
4249 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4250 * don't appear to make the mic bias available from the "line" jack, even
4251 * though the NID used for this jack (0x14) can supply it. The theory is
4252 * that perhaps Acer have included blocking capacitors between the ALC260
4253 * and the output jack. If this turns out to be the case for all such
4254 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4255 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004256 *
4257 * The C20x Tablet series have a mono internal speaker which is controlled
4258 * via the chip's Mono sum widget and pin complex, so include the necessary
4259 * controls for such models. On models without a "mono speaker" the control
4260 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004261 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004262static struct snd_kcontrol_new alc260_acer_mixer[] = {
4263 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4264 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004265 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004266 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004267 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004268 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004269 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004270 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4271 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4272 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4273 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4274 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4275 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4276 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4277 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4278 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4279 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4280 { } /* end */
4281};
4282
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004283/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4284 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4285 */
4286static struct snd_kcontrol_new alc260_will_mixer[] = {
4287 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4288 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4289 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4290 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4291 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4292 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4293 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4294 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4295 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4296 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4297 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4298 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4299 { } /* end */
4300};
4301
4302/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4303 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4304 */
4305static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4306 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4307 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4308 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4309 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4310 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4311 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4312 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4313 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4314 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4315 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4316 { } /* end */
4317};
4318
Kailang Yangdf694da2005-12-05 19:42:22 +01004319/* capture mixer elements */
4320static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004321 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4322 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004323 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4324 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004325 {
4326 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004327 /* The multiple "Capture Source" controls confuse alsamixer
4328 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004329 */
4330 /* .name = "Capture Source", */
4331 .name = "Input Source",
4332 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004333 .info = alc_mux_enum_info,
4334 .get = alc_mux_enum_get,
4335 .put = alc_mux_enum_put,
4336 },
4337 { } /* end */
4338};
4339
Kailang Yangdf694da2005-12-05 19:42:22 +01004340static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4341 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4342 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4343 {
4344 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4345 /* The multiple "Capture Source" controls confuse alsamixer
4346 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004347 */
4348 /* .name = "Capture Source", */
4349 .name = "Input Source",
4350 .count = 1,
4351 .info = alc_mux_enum_info,
4352 .get = alc_mux_enum_get,
4353 .put = alc_mux_enum_put,
4354 },
4355 { } /* end */
4356};
4357
4358/*
4359 * initialization verbs
4360 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361static struct hda_verb alc260_init_verbs[] = {
4362 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004363 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004365 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004367 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004369 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004371 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004373 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004375 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004377 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004379 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4380 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004381 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 /* set connection select to line in (default select for this ADC) */
4383 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004384 /* mute capture amp left and right */
4385 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4386 /* set connection select to line in (default select for this ADC) */
4387 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004388 /* set vol=0 Line-Out mixer amp left and right */
4389 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4390 /* unmute pin widget amp left and right (no gain on this amp) */
4391 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4392 /* set vol=0 HP mixer amp left and right */
4393 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4394 /* unmute pin widget amp left and right (no gain on this amp) */
4395 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4396 /* set vol=0 Mono mixer amp left and right */
4397 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4398 /* unmute pin widget amp left and right (no gain on this amp) */
4399 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4400 /* unmute LINE-2 out pin */
4401 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004402 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4403 * Line In 2 = 0x03
4404 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004405 /* mute analog inputs */
4406 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4407 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4408 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4409 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4410 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004412 /* mute Front out path */
4413 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4414 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4415 /* mute Headphone out path */
4416 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4417 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4418 /* mute Mono out path */
4419 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4420 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 { }
4422};
4423
Takashi Iwai474167d2006-05-17 17:17:43 +02004424#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004425static struct hda_verb alc260_hp_init_verbs[] = {
4426 /* Headphone and output */
4427 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4428 /* mono output */
4429 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4430 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4431 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4432 /* Mic2 (front panel) pin widget for input and vref at 80% */
4433 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4434 /* Line In pin widget for input */
4435 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4436 /* Line-2 pin widget for output */
4437 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4438 /* CD pin widget for input */
4439 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4440 /* unmute amp left and right */
4441 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4442 /* set connection select to line in (default select for this ADC) */
4443 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4444 /* unmute Line-Out mixer amp left and right (volume = 0) */
4445 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4446 /* mute pin widget amp left and right (no gain on this amp) */
4447 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4448 /* unmute HP mixer amp left and right (volume = 0) */
4449 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4450 /* mute pin widget amp left and right (no gain on this amp) */
4451 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004452 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4453 * Line In 2 = 0x03
4454 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004455 /* mute analog inputs */
4456 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4458 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4459 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4460 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004461 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4462 /* Unmute Front out path */
4463 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4464 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4465 /* Unmute Headphone out path */
4466 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4467 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4468 /* Unmute Mono out path */
4469 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4470 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4471 { }
4472};
Takashi Iwai474167d2006-05-17 17:17:43 +02004473#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004474
4475static struct hda_verb alc260_hp_3013_init_verbs[] = {
4476 /* Line out and output */
4477 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4478 /* mono output */
4479 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4480 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4481 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4482 /* Mic2 (front panel) pin widget for input and vref at 80% */
4483 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4484 /* Line In pin widget for input */
4485 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4486 /* Headphone pin widget for output */
4487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4488 /* CD pin widget for input */
4489 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4490 /* unmute amp left and right */
4491 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4492 /* set connection select to line in (default select for this ADC) */
4493 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4494 /* unmute Line-Out mixer amp left and right (volume = 0) */
4495 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4496 /* mute pin widget amp left and right (no gain on this amp) */
4497 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4498 /* unmute HP mixer amp left and right (volume = 0) */
4499 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4500 /* mute pin widget amp left and right (no gain on this amp) */
4501 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004502 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4503 * Line In 2 = 0x03
4504 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004505 /* mute analog inputs */
4506 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4507 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4508 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4509 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4510 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004511 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4512 /* Unmute Front out path */
4513 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4514 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4515 /* Unmute Headphone out path */
4516 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4517 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4518 /* Unmute Mono out path */
4519 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4520 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4521 { }
4522};
4523
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004524/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004525 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4526 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004527 */
4528static struct hda_verb alc260_fujitsu_init_verbs[] = {
4529 /* Disable all GPIOs */
4530 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4531 /* Internal speaker is connected to headphone pin */
4532 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4533 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4534 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004535 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4536 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4537 /* Ensure all other unused pins are disabled and muted. */
4538 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4539 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004540 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004541 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004542 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004543 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4544 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4545 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004546
Jonathan Woithef7ace402006-02-28 11:46:14 +01004547 /* Disable digital (SPDIF) pins */
4548 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4549 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004550
Kailang Yangea1fb292008-08-26 12:58:38 +02004551 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01004552 * when acting as an output.
4553 */
4554 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4555
4556 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004557 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4558 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4559 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4560 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4561 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4562 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4563 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4564 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4565 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004566
Jonathan Woithef7ace402006-02-28 11:46:14 +01004567 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4568 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4569 /* Unmute Line1 pin widget output buffer since it starts as an output.
4570 * If the pin mode is changed by the user the pin mode control will
4571 * take care of enabling the pin's input/output buffers as needed.
4572 * Therefore there's no need to enable the input buffer at this
4573 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004574 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004575 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02004576 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004577 * mixer ctrl)
4578 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004579 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004580
Jonathan Woithef7ace402006-02-28 11:46:14 +01004581 /* Mute capture amp left and right */
4582 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02004583 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01004584 * in (on mic1 pin)
4585 */
4586 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004587
Jonathan Woithef7ace402006-02-28 11:46:14 +01004588 /* Do the same for the second ADC: mute capture input amp and
4589 * set ADC connection to line in (on mic1 pin)
4590 */
4591 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4592 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004593
Jonathan Woithef7ace402006-02-28 11:46:14 +01004594 /* Mute all inputs to mixer widget (even unconnected ones) */
4595 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4596 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4597 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4598 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4599 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4600 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4601 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4602 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004603
4604 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004605};
4606
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004607/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4608 * similar laptops (adapted from Fujitsu init verbs).
4609 */
4610static struct hda_verb alc260_acer_init_verbs[] = {
4611 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4612 * the headphone jack. Turn this on and rely on the standard mute
4613 * methods whenever the user wants to turn these outputs off.
4614 */
4615 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4616 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4617 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4618 /* Internal speaker/Headphone jack is connected to Line-out pin */
4619 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4620 /* Internal microphone/Mic jack is connected to Mic1 pin */
4621 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4622 /* Line In jack is connected to Line1 pin */
4623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004624 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4625 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004626 /* Ensure all other unused pins are disabled and muted. */
4627 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4628 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004629 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4630 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4631 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4632 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4633 /* Disable digital (SPDIF) pins */
4634 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4635 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4636
Kailang Yangea1fb292008-08-26 12:58:38 +02004637 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004638 * bus when acting as outputs.
4639 */
4640 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4641 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4642
4643 /* Start with output sum widgets muted and their output gains at min */
4644 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4645 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4646 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4647 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4648 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4649 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4650 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4651 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4652 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4653
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004654 /* Unmute Line-out pin widget amp left and right
4655 * (no equiv mixer ctrl)
4656 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004657 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004658 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4659 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004660 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4661 * inputs. If the pin mode is changed by the user the pin mode control
4662 * will take care of enabling the pin's input/output buffers as needed.
4663 * Therefore there's no need to enable the input buffer at this
4664 * stage.
4665 */
4666 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4667 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4668
4669 /* Mute capture amp left and right */
4670 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4671 /* Set ADC connection select to match default mixer setting - mic
4672 * (on mic1 pin)
4673 */
4674 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4675
4676 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004677 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004678 */
4679 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004680 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004681
4682 /* Mute all inputs to mixer widget (even unconnected ones) */
4683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4684 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4685 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4686 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4687 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4688 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4689 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4690 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4691
4692 { }
4693};
4694
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004695static struct hda_verb alc260_will_verbs[] = {
4696 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4697 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4698 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4699 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4700 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4701 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4702 {}
4703};
4704
4705static struct hda_verb alc260_replacer_672v_verbs[] = {
4706 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4707 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4708 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4709
4710 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4711 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4712 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4713
4714 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4715 {}
4716};
4717
4718/* toggle speaker-output according to the hp-jack state */
4719static void alc260_replacer_672v_automute(struct hda_codec *codec)
4720{
4721 unsigned int present;
4722
4723 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4724 present = snd_hda_codec_read(codec, 0x0f, 0,
4725 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4726 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004727 snd_hda_codec_write_cache(codec, 0x01, 0,
4728 AC_VERB_SET_GPIO_DATA, 1);
4729 snd_hda_codec_write_cache(codec, 0x0f, 0,
4730 AC_VERB_SET_PIN_WIDGET_CONTROL,
4731 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004732 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004733 snd_hda_codec_write_cache(codec, 0x01, 0,
4734 AC_VERB_SET_GPIO_DATA, 0);
4735 snd_hda_codec_write_cache(codec, 0x0f, 0,
4736 AC_VERB_SET_PIN_WIDGET_CONTROL,
4737 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004738 }
4739}
4740
4741static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4742 unsigned int res)
4743{
4744 if ((res >> 26) == ALC880_HP_EVENT)
4745 alc260_replacer_672v_automute(codec);
4746}
4747
Kailang Yang3f878302008-08-26 13:02:23 +02004748static struct hda_verb alc260_hp_dc7600_verbs[] = {
4749 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
4750 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
4751 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4752 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4753 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4754 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4755 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4756 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4757 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4758 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4759 {}
4760};
4761
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004762/* Test configuration for debugging, modelled after the ALC880 test
4763 * configuration.
4764 */
4765#ifdef CONFIG_SND_DEBUG
4766static hda_nid_t alc260_test_dac_nids[1] = {
4767 0x02,
4768};
4769static hda_nid_t alc260_test_adc_nids[2] = {
4770 0x04, 0x05,
4771};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004772/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02004773 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004774 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004775 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004776static struct hda_input_mux alc260_test_capture_sources[2] = {
4777 {
4778 .num_items = 7,
4779 .items = {
4780 { "MIC1 pin", 0x0 },
4781 { "MIC2 pin", 0x1 },
4782 { "LINE1 pin", 0x2 },
4783 { "LINE2 pin", 0x3 },
4784 { "CD pin", 0x4 },
4785 { "LINE-OUT pin", 0x5 },
4786 { "HP-OUT pin", 0x6 },
4787 },
4788 },
4789 {
4790 .num_items = 8,
4791 .items = {
4792 { "MIC1 pin", 0x0 },
4793 { "MIC2 pin", 0x1 },
4794 { "LINE1 pin", 0x2 },
4795 { "LINE2 pin", 0x3 },
4796 { "CD pin", 0x4 },
4797 { "Mixer", 0x5 },
4798 { "LINE-OUT pin", 0x6 },
4799 { "HP-OUT pin", 0x7 },
4800 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004801 },
4802};
4803static struct snd_kcontrol_new alc260_test_mixer[] = {
4804 /* Output driver widgets */
4805 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4806 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4807 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4808 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4809 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4810 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4811
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004812 /* Modes for retasking pin widgets
4813 * Note: the ALC260 doesn't seem to act on requests to enable mic
4814 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4815 * mention this restriction. At this stage it's not clear whether
4816 * this behaviour is intentional or is a hardware bug in chip
4817 * revisions available at least up until early 2006. Therefore for
4818 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4819 * choices, but if it turns out that the lack of mic bias for these
4820 * NIDs is intentional we could change their modes from
4821 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4822 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004823 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4824 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4825 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4826 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4827 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4828 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4829
4830 /* Loopback mixer controls */
4831 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4832 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4833 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4834 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4835 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4836 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4837 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4838 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4839 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4840 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4841 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4842 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4843 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4844 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4845 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4846 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004847
4848 /* Controls for GPIO pins, assuming they are configured as outputs */
4849 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4850 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4851 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4852 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4853
Jonathan Woithe92621f12006-02-28 11:47:47 +01004854 /* Switches to allow the digital IO pins to be enabled. The datasheet
4855 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02004856 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01004857 */
4858 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4859 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4860
Jonathan Woithef8225f62008-01-08 12:16:54 +01004861 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4862 * this output to turn on an external amplifier.
4863 */
4864 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4865 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4866
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004867 { } /* end */
4868};
4869static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004870 /* Enable all GPIOs as outputs with an initial value of 0 */
4871 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4872 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4873 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4874
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004875 /* Enable retasking pins as output, initially without power amp */
4876 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4877 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4878 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4879 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4880 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4881 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4882
Jonathan Woithe92621f12006-02-28 11:47:47 +01004883 /* Disable digital (SPDIF) pins initially, but users can enable
4884 * them via a mixer switch. In the case of SPDIF-out, this initverb
4885 * payload also sets the generation to 0, output to be in "consumer"
4886 * PCM format, copyright asserted, no pre-emphasis and no validity
4887 * control.
4888 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004889 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4890 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4891
Kailang Yangea1fb292008-08-26 12:58:38 +02004892 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004893 * OUT1 sum bus when acting as an output.
4894 */
4895 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4896 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4897 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4898 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4899
4900 /* Start with output sum widgets muted and their output gains at min */
4901 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4902 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4903 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4904 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4905 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4906 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4907 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4908 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4909 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4910
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004911 /* Unmute retasking pin widget output buffers since the default
4912 * state appears to be output. As the pin mode is changed by the
4913 * user the pin mode control will take care of enabling the pin's
4914 * input/output buffers as needed.
4915 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004916 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4917 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4918 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4919 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4920 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4921 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4922 /* Also unmute the mono-out pin widget */
4923 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4924
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004925 /* Mute capture amp left and right */
4926 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004927 /* Set ADC connection select to match default mixer setting (mic1
4928 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004929 */
4930 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4931
4932 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004933 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004934 */
4935 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4936 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4937
4938 /* Mute all inputs to mixer widget (even unconnected ones) */
4939 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4940 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4941 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4942 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4943 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4944 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4945 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4946 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4947
4948 { }
4949};
4950#endif
4951
Takashi Iwai63300792008-01-24 15:31:36 +01004952#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4953#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004955#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4956#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4957
Kailang Yangdf694da2005-12-05 19:42:22 +01004958/*
4959 * for BIOS auto-configuration
4960 */
4961
4962static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4963 const char *pfx)
4964{
4965 hda_nid_t nid_vol;
4966 unsigned long vol_val, sw_val;
4967 char name[32];
4968 int err;
4969
4970 if (nid >= 0x0f && nid < 0x11) {
4971 nid_vol = nid - 0x7;
4972 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4973 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4974 } else if (nid == 0x11) {
4975 nid_vol = nid - 0x7;
4976 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4977 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4978 } else if (nid >= 0x12 && nid <= 0x15) {
4979 nid_vol = 0x08;
4980 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4981 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4982 } else
4983 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02004984
Kailang Yangdf694da2005-12-05 19:42:22 +01004985 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004986 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4987 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004988 return err;
4989 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004990 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4991 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004992 return err;
4993 return 1;
4994}
4995
4996/* add playback controls from the parsed DAC table */
4997static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4998 const struct auto_pin_cfg *cfg)
4999{
5000 hda_nid_t nid;
5001 int err;
5002
5003 spec->multiout.num_dacs = 1;
5004 spec->multiout.dac_nids = spec->private_dac_nids;
5005 spec->multiout.dac_nids[0] = 0x02;
5006
5007 nid = cfg->line_out_pins[0];
5008 if (nid) {
5009 err = alc260_add_playback_controls(spec, nid, "Front");
5010 if (err < 0)
5011 return err;
5012 }
5013
Takashi Iwai82bc9552006-03-21 11:24:42 +01005014 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005015 if (nid) {
5016 err = alc260_add_playback_controls(spec, nid, "Speaker");
5017 if (err < 0)
5018 return err;
5019 }
5020
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005021 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005022 if (nid) {
5023 err = alc260_add_playback_controls(spec, nid, "Headphone");
5024 if (err < 0)
5025 return err;
5026 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005027 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005028}
5029
5030/* create playback/capture controls for input pins */
5031static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5032 const struct auto_pin_cfg *cfg)
5033{
Kailang Yangdf694da2005-12-05 19:42:22 +01005034 struct hda_input_mux *imux = &spec->private_imux;
5035 int i, err, idx;
5036
5037 for (i = 0; i < AUTO_PIN_LAST; i++) {
5038 if (cfg->input_pins[i] >= 0x12) {
5039 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005040 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005041 auto_pin_cfg_labels[i], idx,
5042 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005043 if (err < 0)
5044 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005045 imux->items[imux->num_items].label =
5046 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005047 imux->items[imux->num_items].index = idx;
5048 imux->num_items++;
5049 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005050 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005051 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005052 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005053 auto_pin_cfg_labels[i], idx,
5054 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005055 if (err < 0)
5056 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005057 imux->items[imux->num_items].label =
5058 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005059 imux->items[imux->num_items].index = idx;
5060 imux->num_items++;
5061 }
5062 }
5063 return 0;
5064}
5065
5066static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5067 hda_nid_t nid, int pin_type,
5068 int sel_idx)
5069{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005070 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005071 /* need the manual connection? */
5072 if (nid >= 0x12) {
5073 int idx = nid - 0x12;
5074 snd_hda_codec_write(codec, idx + 0x0b, 0,
5075 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005076 }
5077}
5078
5079static void alc260_auto_init_multi_out(struct hda_codec *codec)
5080{
5081 struct alc_spec *spec = codec->spec;
5082 hda_nid_t nid;
5083
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005084 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005085 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005086 if (nid) {
5087 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5088 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5089 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005090
Takashi Iwai82bc9552006-03-21 11:24:42 +01005091 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005092 if (nid)
5093 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5094
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005095 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005096 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005097 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005098}
Kailang Yangdf694da2005-12-05 19:42:22 +01005099
5100#define ALC260_PIN_CD_NID 0x16
5101static void alc260_auto_init_analog_input(struct hda_codec *codec)
5102{
5103 struct alc_spec *spec = codec->spec;
5104 int i;
5105
5106 for (i = 0; i < AUTO_PIN_LAST; i++) {
5107 hda_nid_t nid = spec->autocfg.input_pins[i];
5108 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005109 snd_hda_codec_write(codec, nid, 0,
5110 AC_VERB_SET_PIN_WIDGET_CONTROL,
5111 i <= AUTO_PIN_FRONT_MIC ?
5112 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01005113 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005114 snd_hda_codec_write(codec, nid, 0,
5115 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005116 AMP_OUT_MUTE);
5117 }
5118 }
5119}
5120
5121/*
5122 * generic initialization of ADC, input mixers and output mixers
5123 */
5124static struct hda_verb alc260_volume_init_verbs[] = {
5125 /*
5126 * Unmute ADC0-1 and set the default input to mic-in
5127 */
5128 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5129 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5130 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5131 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005132
Kailang Yangdf694da2005-12-05 19:42:22 +01005133 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5134 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005135 * Note: PASD motherboards uses the Line In 2 as the input for
5136 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005137 */
5138 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005139 /* mute analog inputs */
5140 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5141 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5142 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5143 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5144 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005145
5146 /*
5147 * Set up output mixers (0x08 - 0x0a)
5148 */
5149 /* set vol=0 to output mixers */
5150 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5151 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5152 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5153 /* set up input amps for analog loopback */
5154 /* Amp Indices: DAC = 0, mixer = 1 */
5155 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5156 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5157 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5158 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5159 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5160 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005161
Kailang Yangdf694da2005-12-05 19:42:22 +01005162 { }
5163};
5164
5165static int alc260_parse_auto_config(struct hda_codec *codec)
5166{
5167 struct alc_spec *spec = codec->spec;
5168 unsigned int wcap;
5169 int err;
5170 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5171
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005172 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5173 alc260_ignore);
5174 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005175 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005176 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5177 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005178 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005179 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01005180 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005181 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5182 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005183 return err;
5184
5185 spec->multiout.max_channels = 2;
5186
5187 if (spec->autocfg.dig_out_pin)
5188 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
5189 if (spec->kctl_alloc)
5190 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
5191
5192 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
5193
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005194 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01005195 spec->input_mux = &spec->private_imux;
5196
5197 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005198 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01005199 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
Takashi Iwai67ebcb02008-02-19 15:03:57 +01005200 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Kailang Yangdf694da2005-12-05 19:42:22 +01005201 spec->adc_nids = alc260_adc_nids_alt;
5202 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
5203 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01005204 } else {
5205 spec->adc_nids = alc260_adc_nids;
5206 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
5207 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01005208 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01005209 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01005210
5211 return 1;
5212}
5213
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005214/* additional initialization for auto-configuration model */
5215static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005216{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005217 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005218 alc260_auto_init_multi_out(codec);
5219 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005220 if (spec->unsol_event)
5221 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005222}
5223
Takashi Iwaicb53c622007-08-10 17:21:45 +02005224#ifdef CONFIG_SND_HDA_POWER_SAVE
5225static struct hda_amp_list alc260_loopbacks[] = {
5226 { 0x07, HDA_INPUT, 0 },
5227 { 0x07, HDA_INPUT, 1 },
5228 { 0x07, HDA_INPUT, 2 },
5229 { 0x07, HDA_INPUT, 3 },
5230 { 0x07, HDA_INPUT, 4 },
5231 { } /* end */
5232};
5233#endif
5234
Kailang Yangdf694da2005-12-05 19:42:22 +01005235/*
5236 * ALC260 configurations
5237 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005238static const char *alc260_models[ALC260_MODEL_LAST] = {
5239 [ALC260_BASIC] = "basic",
5240 [ALC260_HP] = "hp",
5241 [ALC260_HP_3013] = "hp-3013",
5242 [ALC260_FUJITSU_S702X] = "fujitsu",
5243 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005244 [ALC260_WILL] = "will",
5245 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005246#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005247 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005248#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005249 [ALC260_AUTO] = "auto",
5250};
5251
5252static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005253 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005254 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005255 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005256 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005257 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005258 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005259 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005260 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5261 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5262 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5263 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5264 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5265 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5266 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5267 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5268 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005269 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005270 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005271 {}
5272};
5273
Kailang Yangdf694da2005-12-05 19:42:22 +01005274static struct alc_config_preset alc260_presets[] = {
5275 [ALC260_BASIC] = {
5276 .mixers = { alc260_base_output_mixer,
5277 alc260_input_mixer,
5278 alc260_pc_beep_mixer,
5279 alc260_capture_mixer },
5280 .init_verbs = { alc260_init_verbs },
5281 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5282 .dac_nids = alc260_dac_nids,
5283 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5284 .adc_nids = alc260_adc_nids,
5285 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5286 .channel_mode = alc260_modes,
5287 .input_mux = &alc260_capture_source,
5288 },
5289 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005290 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005291 alc260_input_mixer,
5292 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005293 .init_verbs = { alc260_init_verbs,
5294 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005295 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5296 .dac_nids = alc260_dac_nids,
5297 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5298 .adc_nids = alc260_hp_adc_nids,
5299 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5300 .channel_mode = alc260_modes,
5301 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005302 .unsol_event = alc260_hp_unsol_event,
5303 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005304 },
Kailang Yang3f878302008-08-26 13:02:23 +02005305 [ALC260_HP_DC7600] = {
5306 .mixers = { alc260_hp_dc7600_mixer,
5307 alc260_input_mixer,
5308 alc260_capture_alt_mixer },
5309 .init_verbs = { alc260_init_verbs,
5310 alc260_hp_dc7600_verbs },
5311 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5312 .dac_nids = alc260_dac_nids,
5313 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5314 .adc_nids = alc260_hp_adc_nids,
5315 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5316 .channel_mode = alc260_modes,
5317 .input_mux = &alc260_capture_source,
5318 .unsol_event = alc260_hp_3012_unsol_event,
5319 .init_hook = alc260_hp_3012_automute,
5320 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005321 [ALC260_HP_3013] = {
5322 .mixers = { alc260_hp_3013_mixer,
5323 alc260_input_mixer,
5324 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005325 .init_verbs = { alc260_hp_3013_init_verbs,
5326 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005327 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5328 .dac_nids = alc260_dac_nids,
5329 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5330 .adc_nids = alc260_hp_adc_nids,
5331 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5332 .channel_mode = alc260_modes,
5333 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005334 .unsol_event = alc260_hp_3013_unsol_event,
5335 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005336 },
5337 [ALC260_FUJITSU_S702X] = {
5338 .mixers = { alc260_fujitsu_mixer,
5339 alc260_capture_mixer },
5340 .init_verbs = { alc260_fujitsu_init_verbs },
5341 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5342 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005343 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5344 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005345 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5346 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005347 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5348 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005349 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005350 [ALC260_ACER] = {
5351 .mixers = { alc260_acer_mixer,
5352 alc260_capture_mixer },
5353 .init_verbs = { alc260_acer_init_verbs },
5354 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5355 .dac_nids = alc260_dac_nids,
5356 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5357 .adc_nids = alc260_dual_adc_nids,
5358 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5359 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005360 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5361 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005362 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005363 [ALC260_WILL] = {
5364 .mixers = { alc260_will_mixer,
5365 alc260_capture_mixer },
5366 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5367 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5368 .dac_nids = alc260_dac_nids,
5369 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5370 .adc_nids = alc260_adc_nids,
5371 .dig_out_nid = ALC260_DIGOUT_NID,
5372 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5373 .channel_mode = alc260_modes,
5374 .input_mux = &alc260_capture_source,
5375 },
5376 [ALC260_REPLACER_672V] = {
5377 .mixers = { alc260_replacer_672v_mixer,
5378 alc260_capture_mixer },
5379 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5380 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5381 .dac_nids = alc260_dac_nids,
5382 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5383 .adc_nids = alc260_adc_nids,
5384 .dig_out_nid = ALC260_DIGOUT_NID,
5385 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5386 .channel_mode = alc260_modes,
5387 .input_mux = &alc260_capture_source,
5388 .unsol_event = alc260_replacer_672v_unsol_event,
5389 .init_hook = alc260_replacer_672v_automute,
5390 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005391#ifdef CONFIG_SND_DEBUG
5392 [ALC260_TEST] = {
5393 .mixers = { alc260_test_mixer,
5394 alc260_capture_mixer },
5395 .init_verbs = { alc260_test_init_verbs },
5396 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5397 .dac_nids = alc260_test_dac_nids,
5398 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5399 .adc_nids = alc260_test_adc_nids,
5400 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5401 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005402 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5403 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005404 },
5405#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005406};
5407
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408static int patch_alc260(struct hda_codec *codec)
5409{
5410 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005411 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005413 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 if (spec == NULL)
5415 return -ENOMEM;
5416
5417 codec->spec = spec;
5418
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005419 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5420 alc260_models,
5421 alc260_cfg_tbl);
5422 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005423 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5424 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005425 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005426 }
5427
Kailang Yangdf694da2005-12-05 19:42:22 +01005428 if (board_config == ALC260_AUTO) {
5429 /* automatic parse from the BIOS config */
5430 err = alc260_parse_auto_config(codec);
5431 if (err < 0) {
5432 alc_free(codec);
5433 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005434 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005435 printk(KERN_INFO
5436 "hda_codec: Cannot set up configuration "
5437 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005438 board_config = ALC260_BASIC;
5439 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441
Kailang Yangdf694da2005-12-05 19:42:22 +01005442 if (board_config != ALC260_AUTO)
5443 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444
5445 spec->stream_name_analog = "ALC260 Analog";
5446 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5447 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5448
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005449 spec->stream_name_digital = "ALC260 Digital";
5450 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5451 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5452
Takashi Iwai2134ea42008-01-10 16:53:55 +01005453 spec->vmaster_nid = 0x08;
5454
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005456 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005457 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005458#ifdef CONFIG_SND_HDA_POWER_SAVE
5459 if (!spec->loopback.amplist)
5460 spec->loopback.amplist = alc260_loopbacks;
5461#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462
5463 return 0;
5464}
5465
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005466
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467/*
5468 * ALC882 support
5469 *
5470 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5471 * configuration. Each pin widget can choose any input DACs and a mixer.
5472 * Each ADC is connected from a mixer of all inputs. This makes possible
5473 * 6-channel independent captures.
5474 *
5475 * In addition, an independent DAC for the multi-playback (not used in this
5476 * driver yet).
5477 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005478#define ALC882_DIGOUT_NID 0x06
5479#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005481static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 { 8, NULL }
5483};
5484
5485static hda_nid_t alc882_dac_nids[4] = {
5486 /* front, rear, clfe, rear_surr */
5487 0x02, 0x03, 0x04, 0x05
5488};
5489
Kailang Yangdf694da2005-12-05 19:42:22 +01005490/* identical with ALC880 */
5491#define alc882_adc_nids alc880_adc_nids
5492#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493
Takashi Iwaie1406342008-02-11 18:32:32 +01005494static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5495static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5496
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497/* input MUX */
5498/* FIXME: should be a matrix-type input source selection */
5499
5500static struct hda_input_mux alc882_capture_source = {
5501 .num_items = 4,
5502 .items = {
5503 { "Mic", 0x0 },
5504 { "Front Mic", 0x1 },
5505 { "Line", 0x2 },
5506 { "CD", 0x4 },
5507 },
5508};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509#define alc882_mux_enum_info alc_mux_enum_info
5510#define alc882_mux_enum_get alc_mux_enum_get
5511
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005512static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5513 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514{
5515 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5516 struct alc_spec *spec = codec->spec;
5517 const struct hda_input_mux *imux = spec->input_mux;
5518 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai88c71a92008-02-14 17:27:17 +01005519 hda_nid_t nid = spec->capsrc_nids ?
5520 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5522 unsigned int i, idx;
5523
5524 idx = ucontrol->value.enumerated.item[0];
5525 if (idx >= imux->num_items)
5526 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005527 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 return 0;
5529 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005530 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5531 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005532 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005533 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 }
5535 *cur_val = idx;
5536 return 1;
5537}
5538
Kailang Yangdf694da2005-12-05 19:42:22 +01005539/*
Kailang Yang272a5272007-05-14 11:00:38 +02005540 * 2ch mode
5541 */
5542static struct hda_verb alc882_3ST_ch2_init[] = {
5543 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5544 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5545 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5546 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5547 { } /* end */
5548};
5549
5550/*
5551 * 6ch mode
5552 */
5553static struct hda_verb alc882_3ST_ch6_init[] = {
5554 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5555 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5556 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5557 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5558 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5559 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5560 { } /* end */
5561};
5562
5563static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5564 { 2, alc882_3ST_ch2_init },
5565 { 6, alc882_3ST_ch6_init },
5566};
5567
5568/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005569 * 6ch mode
5570 */
5571static struct hda_verb alc882_sixstack_ch6_init[] = {
5572 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5573 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5574 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5575 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5576 { } /* end */
5577};
5578
5579/*
5580 * 8ch mode
5581 */
5582static struct hda_verb alc882_sixstack_ch8_init[] = {
5583 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5584 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5585 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5586 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5587 { } /* end */
5588};
5589
5590static struct hda_channel_mode alc882_sixstack_modes[2] = {
5591 { 6, alc882_sixstack_ch6_init },
5592 { 8, alc882_sixstack_ch8_init },
5593};
5594
Takashi Iwai87350ad2007-08-16 18:19:38 +02005595/*
5596 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5597 */
5598
5599/*
5600 * 2ch mode
5601 */
5602static struct hda_verb alc885_mbp_ch2_init[] = {
5603 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5604 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5605 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5606 { } /* end */
5607};
5608
5609/*
5610 * 6ch mode
5611 */
5612static struct hda_verb alc885_mbp_ch6_init[] = {
5613 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5614 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5615 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5616 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5617 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5618 { } /* end */
5619};
5620
5621static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5622 { 2, alc885_mbp_ch2_init },
5623 { 6, alc885_mbp_ch6_init },
5624};
5625
5626
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5628 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5629 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005630static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005631 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005632 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005633 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005634 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005635 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5636 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005637 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5638 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005639 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005640 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5642 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5643 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5644 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5645 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005647 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5649 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005650 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5652 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5653 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 { } /* end */
5655};
5656
Takashi Iwai87350ad2007-08-16 18:19:38 +02005657static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005658 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5659 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5660 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5661 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5662 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5663 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5665 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005666 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005667 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5668 { } /* end */
5669};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005670static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5671 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5672 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5673 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5674 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5675 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5676 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5677 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5678 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5679 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5680 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5681 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5682 { } /* end */
5683};
5684
Kailang Yang272a5272007-05-14 11:00:38 +02005685static struct snd_kcontrol_new alc882_targa_mixer[] = {
5686 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5687 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5688 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5689 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5690 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5691 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5692 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5693 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5694 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005695 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005696 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5697 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005698 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005699 { } /* end */
5700};
5701
5702/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5703 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5704 */
5705static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5706 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5707 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5708 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5709 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5710 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5711 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5712 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5713 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5714 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5715 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5716 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5717 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005718 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005719 { } /* end */
5720};
5721
Takashi Iwai914759b2007-09-06 14:52:04 +02005722static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5723 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5724 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5725 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5726 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5727 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5728 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5729 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5731 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5732 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5733 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5734 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5735 { } /* end */
5736};
5737
Kailang Yangdf694da2005-12-05 19:42:22 +01005738static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5739 {
5740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5741 .name = "Channel Mode",
5742 .info = alc_ch_mode_info,
5743 .get = alc_ch_mode_get,
5744 .put = alc_ch_mode_put,
5745 },
5746 { } /* end */
5747};
5748
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749static struct hda_verb alc882_init_verbs[] = {
5750 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005751 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5752 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5753 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005755 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5756 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5757 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005759 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5760 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5761 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005763 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5764 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5765 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005767 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005768 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005769 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005771 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005772 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005773 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005775 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005776 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005777 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005779 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005780 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005781 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005783 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005784 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005785 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5786 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005787 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005788 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5789 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005790 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005791 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5792 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5793 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5794 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5795 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005797 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
5799 /* FIXME: use matrix-type input source selection */
5800 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5801 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005802 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5803 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5804 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5805 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005807 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5808 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5809 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5810 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005812 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5813 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5814 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5815 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5816 /* ADC1: mute amp left and right */
5817 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005818 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005819 /* ADC2: mute amp left and right */
5820 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005821 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005822 /* ADC3: mute amp left and right */
5823 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005824 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825
5826 { }
5827};
5828
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005829static struct hda_verb alc882_eapd_verbs[] = {
5830 /* change to EAPD mode */
5831 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005832 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005833 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005834};
5835
Tobin Davis9102cd12006-12-15 10:02:12 +01005836/* Mac Pro test */
5837static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5838 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5839 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5840 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5841 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5842 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5843 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5844 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5845 { } /* end */
5846};
5847
5848static struct hda_verb alc882_macpro_init_verbs[] = {
5849 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5850 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5851 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5852 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5853 /* Front Pin: output 0 (0x0c) */
5854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5855 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5856 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5857 /* Front Mic pin: input vref at 80% */
5858 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5859 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5860 /* Speaker: output */
5861 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5862 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5863 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5864 /* Headphone output (output 0 - 0x0c) */
5865 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5866 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5867 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5868
5869 /* FIXME: use matrix-type input source selection */
5870 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5871 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5872 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5873 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5874 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5875 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5876 /* Input mixer2 */
5877 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5878 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5879 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5880 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5881 /* Input mixer3 */
5882 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5883 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5884 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5885 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5886 /* ADC1: mute amp left and right */
5887 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5888 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5889 /* ADC2: mute amp left and right */
5890 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5891 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5892 /* ADC3: mute amp left and right */
5893 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5894 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5895
5896 { }
5897};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005898
Takashi Iwai87350ad2007-08-16 18:19:38 +02005899/* Macbook Pro rev3 */
5900static struct hda_verb alc885_mbp3_init_verbs[] = {
5901 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5902 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5903 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5904 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5905 /* Rear mixer */
5906 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5907 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5908 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5909 /* Front Pin: output 0 (0x0c) */
5910 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5911 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5912 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5913 /* HP Pin: output 0 (0x0d) */
5914 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5915 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5916 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5917 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5918 /* Mic (rear) pin: input vref at 80% */
5919 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5920 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5921 /* Front Mic pin: input vref at 80% */
5922 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5923 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5924 /* Line In pin: use output 1 when in LineOut mode */
5925 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5926 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5927 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5928
5929 /* FIXME: use matrix-type input source selection */
5930 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5931 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5932 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5933 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5934 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5935 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5936 /* Input mixer2 */
5937 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5938 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5939 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5940 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5941 /* Input mixer3 */
5942 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5943 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5944 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5945 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5946 /* ADC1: mute amp left and right */
5947 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5948 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5949 /* ADC2: mute amp left and right */
5950 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5951 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5952 /* ADC3: mute amp left and right */
5953 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5954 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5955
5956 { }
5957};
5958
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005959/* iMac 24 mixer. */
5960static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5961 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5962 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5963 { } /* end */
5964};
5965
5966/* iMac 24 init verbs. */
5967static struct hda_verb alc885_imac24_init_verbs[] = {
5968 /* Internal speakers: output 0 (0x0c) */
5969 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5970 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5971 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5972 /* Internal speakers: output 0 (0x0c) */
5973 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5974 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5975 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5976 /* Headphone: output 0 (0x0c) */
5977 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5978 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5979 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5980 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5981 /* Front Mic: input vref at 80% */
5982 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5983 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5984 { }
5985};
5986
5987/* Toggle speaker-output according to the hp-jack state */
5988static void alc885_imac24_automute(struct hda_codec *codec)
5989{
5990 unsigned int present;
5991
5992 present = snd_hda_codec_read(codec, 0x14, 0,
5993 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005994 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5995 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5996 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5997 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005998}
5999
6000/* Processes unsolicited events. */
6001static void alc885_imac24_unsol_event(struct hda_codec *codec,
6002 unsigned int res)
6003{
6004 /* Headphone insertion or removal. */
6005 if ((res >> 26) == ALC880_HP_EVENT)
6006 alc885_imac24_automute(codec);
6007}
6008
Takashi Iwai87350ad2007-08-16 18:19:38 +02006009static void alc885_mbp3_automute(struct hda_codec *codec)
6010{
6011 unsigned int present;
6012
6013 present = snd_hda_codec_read(codec, 0x15, 0,
6014 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6015 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6016 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6017 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6018 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6019
6020}
6021static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6022 unsigned int res)
6023{
6024 /* Headphone insertion or removal. */
6025 if ((res >> 26) == ALC880_HP_EVENT)
6026 alc885_mbp3_automute(codec);
6027}
6028
6029
Kailang Yang272a5272007-05-14 11:00:38 +02006030static struct hda_verb alc882_targa_verbs[] = {
6031 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6032 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6033
6034 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6035 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006036
Kailang Yang272a5272007-05-14 11:00:38 +02006037 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6038 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6039 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6040
6041 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6042 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6043 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6044 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6045 { } /* end */
6046};
6047
6048/* toggle speaker-output according to the hp-jack state */
6049static void alc882_targa_automute(struct hda_codec *codec)
6050{
6051 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006052
Kailang Yang272a5272007-05-14 11:00:38 +02006053 present = snd_hda_codec_read(codec, 0x14, 0,
6054 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006055 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6056 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006057 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6058 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006059}
6060
6061static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6062{
6063 /* Looks like the unsol event is incompatible with the standard
6064 * definition. 4bit tag is placed at 26 bit!
6065 */
6066 if (((res >> 26) == ALC880_HP_EVENT)) {
6067 alc882_targa_automute(codec);
6068 }
6069}
6070
6071static struct hda_verb alc882_asus_a7j_verbs[] = {
6072 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6073 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6074
6075 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6076 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6077 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006078
Kailang Yang272a5272007-05-14 11:00:38 +02006079 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6080 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6081 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6082
6083 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6084 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6085 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6086 { } /* end */
6087};
6088
Takashi Iwai914759b2007-09-06 14:52:04 +02006089static struct hda_verb alc882_asus_a7m_verbs[] = {
6090 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6091 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6092
6093 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6094 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6095 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006096
Takashi Iwai914759b2007-09-06 14:52:04 +02006097 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6098 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6099 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6100
6101 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6102 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6103 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6104 { } /* end */
6105};
6106
Tobin Davis9102cd12006-12-15 10:02:12 +01006107static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6108{
6109 unsigned int gpiostate, gpiomask, gpiodir;
6110
6111 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6112 AC_VERB_GET_GPIO_DATA, 0);
6113
6114 if (!muted)
6115 gpiostate |= (1 << pin);
6116 else
6117 gpiostate &= ~(1 << pin);
6118
6119 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6120 AC_VERB_GET_GPIO_MASK, 0);
6121 gpiomask |= (1 << pin);
6122
6123 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6124 AC_VERB_GET_GPIO_DIRECTION, 0);
6125 gpiodir |= (1 << pin);
6126
6127
6128 snd_hda_codec_write(codec, codec->afg, 0,
6129 AC_VERB_SET_GPIO_MASK, gpiomask);
6130 snd_hda_codec_write(codec, codec->afg, 0,
6131 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6132
6133 msleep(1);
6134
6135 snd_hda_codec_write(codec, codec->afg, 0,
6136 AC_VERB_SET_GPIO_DATA, gpiostate);
6137}
6138
Takashi Iwai7debbe52007-08-16 15:01:03 +02006139/* set up GPIO at initialization */
6140static void alc885_macpro_init_hook(struct hda_codec *codec)
6141{
6142 alc882_gpio_mute(codec, 0, 0);
6143 alc882_gpio_mute(codec, 1, 0);
6144}
6145
6146/* set up GPIO and update auto-muting at initialization */
6147static void alc885_imac24_init_hook(struct hda_codec *codec)
6148{
6149 alc885_macpro_init_hook(codec);
6150 alc885_imac24_automute(codec);
6151}
6152
Kailang Yangdf694da2005-12-05 19:42:22 +01006153/*
6154 * generic initialization of ADC, input mixers and output mixers
6155 */
6156static struct hda_verb alc882_auto_init_verbs[] = {
6157 /*
6158 * Unmute ADC0-2 and set the default input to mic-in
6159 */
6160 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6161 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6162 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6163 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6164 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6165 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6166
Takashi Iwaicb53c622007-08-10 17:21:45 +02006167 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006168 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006169 * Note: PASD motherboards uses the Line In 2 as the input for
6170 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006171 */
6172 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006173 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6174 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6175 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6176 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6177 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006178
6179 /*
6180 * Set up output mixers (0x0c - 0x0f)
6181 */
6182 /* set vol=0 to output mixers */
6183 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6184 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6185 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6186 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6187 /* set up input amps for analog loopback */
6188 /* Amp Indices: DAC = 0, mixer = 1 */
6189 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6190 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6191 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6192 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6193 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6194 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6195 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6196 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6197 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6198 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6199
6200 /* FIXME: use matrix-type input source selection */
6201 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6202 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6203 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6204 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6205 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6206 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6207 /* Input mixer2 */
6208 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6209 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6210 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6211 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6212 /* Input mixer3 */
6213 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6214 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6215 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6216 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6217
6218 { }
6219};
6220
6221/* capture mixer elements */
6222static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
6223 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6224 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6225 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6226 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6227 {
6228 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6229 /* The multiple "Capture Source" controls confuse alsamixer
6230 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006231 */
6232 /* .name = "Capture Source", */
6233 .name = "Input Source",
6234 .count = 2,
6235 .info = alc882_mux_enum_info,
6236 .get = alc882_mux_enum_get,
6237 .put = alc882_mux_enum_put,
6238 },
6239 { } /* end */
6240};
6241
6242static struct snd_kcontrol_new alc882_capture_mixer[] = {
6243 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
6244 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
6245 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
6246 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
6247 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
6248 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
6249 {
6250 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6251 /* The multiple "Capture Source" controls confuse alsamixer
6252 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006253 */
6254 /* .name = "Capture Source", */
6255 .name = "Input Source",
6256 .count = 3,
6257 .info = alc882_mux_enum_info,
6258 .get = alc882_mux_enum_get,
6259 .put = alc882_mux_enum_put,
6260 },
6261 { } /* end */
6262};
6263
Takashi Iwaicb53c622007-08-10 17:21:45 +02006264#ifdef CONFIG_SND_HDA_POWER_SAVE
6265#define alc882_loopbacks alc880_loopbacks
6266#endif
6267
Kailang Yangdf694da2005-12-05 19:42:22 +01006268/* pcm configuration: identiacal with ALC880 */
6269#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6270#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6271#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6272#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6273
6274/*
6275 * configuration and preset
6276 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006277static const char *alc882_models[ALC882_MODEL_LAST] = {
6278 [ALC882_3ST_DIG] = "3stack-dig",
6279 [ALC882_6ST_DIG] = "6stack-dig",
6280 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006281 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006282 [ALC882_TARGA] = "targa",
6283 [ALC882_ASUS_A7J] = "asus-a7j",
6284 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006285 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006286 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006287 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006288 [ALC882_AUTO] = "auto",
6289};
6290
6291static struct snd_pci_quirk alc882_cfg_tbl[] = {
6292 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006293 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006294 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006295 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006296 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006297 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006298 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006299 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006300 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006301 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6302 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6303 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006304 {}
6305};
6306
6307static struct alc_config_preset alc882_presets[] = {
6308 [ALC882_3ST_DIG] = {
6309 .mixers = { alc882_base_mixer },
6310 .init_verbs = { alc882_init_verbs },
6311 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6312 .dac_nids = alc882_dac_nids,
6313 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006314 .dig_in_nid = ALC882_DIGIN_NID,
6315 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6316 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006317 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006318 .input_mux = &alc882_capture_source,
6319 },
6320 [ALC882_6ST_DIG] = {
6321 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6322 .init_verbs = { alc882_init_verbs },
6323 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6324 .dac_nids = alc882_dac_nids,
6325 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006326 .dig_in_nid = ALC882_DIGIN_NID,
6327 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6328 .channel_mode = alc882_sixstack_modes,
6329 .input_mux = &alc882_capture_source,
6330 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006331 [ALC882_ARIMA] = {
6332 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6333 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6334 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6335 .dac_nids = alc882_dac_nids,
6336 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6337 .channel_mode = alc882_sixstack_modes,
6338 .input_mux = &alc882_capture_source,
6339 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006340 [ALC882_W2JC] = {
6341 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6342 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6343 alc880_gpio1_init_verbs },
6344 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6345 .dac_nids = alc882_dac_nids,
6346 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6347 .channel_mode = alc880_threestack_modes,
6348 .need_dac_fix = 1,
6349 .input_mux = &alc882_capture_source,
6350 .dig_out_nid = ALC882_DIGOUT_NID,
6351 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006352 [ALC885_MBP3] = {
6353 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6354 .init_verbs = { alc885_mbp3_init_verbs,
6355 alc880_gpio1_init_verbs },
6356 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6357 .dac_nids = alc882_dac_nids,
6358 .channel_mode = alc885_mbp_6ch_modes,
6359 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6360 .input_mux = &alc882_capture_source,
6361 .dig_out_nid = ALC882_DIGOUT_NID,
6362 .dig_in_nid = ALC882_DIGIN_NID,
6363 .unsol_event = alc885_mbp3_unsol_event,
6364 .init_hook = alc885_mbp3_automute,
6365 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006366 [ALC885_MACPRO] = {
6367 .mixers = { alc882_macpro_mixer },
6368 .init_verbs = { alc882_macpro_init_verbs },
6369 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6370 .dac_nids = alc882_dac_nids,
6371 .dig_out_nid = ALC882_DIGOUT_NID,
6372 .dig_in_nid = ALC882_DIGIN_NID,
6373 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6374 .channel_mode = alc882_ch_modes,
6375 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006376 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006377 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006378 [ALC885_IMAC24] = {
6379 .mixers = { alc885_imac24_mixer },
6380 .init_verbs = { alc885_imac24_init_verbs },
6381 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6382 .dac_nids = alc882_dac_nids,
6383 .dig_out_nid = ALC882_DIGOUT_NID,
6384 .dig_in_nid = ALC882_DIGIN_NID,
6385 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6386 .channel_mode = alc882_ch_modes,
6387 .input_mux = &alc882_capture_source,
6388 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006389 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006390 },
Kailang Yang272a5272007-05-14 11:00:38 +02006391 [ALC882_TARGA] = {
6392 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6393 alc882_capture_mixer },
6394 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6395 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6396 .dac_nids = alc882_dac_nids,
6397 .dig_out_nid = ALC882_DIGOUT_NID,
6398 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6399 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006400 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006401 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6402 .channel_mode = alc882_3ST_6ch_modes,
6403 .need_dac_fix = 1,
6404 .input_mux = &alc882_capture_source,
6405 .unsol_event = alc882_targa_unsol_event,
6406 .init_hook = alc882_targa_automute,
6407 },
6408 [ALC882_ASUS_A7J] = {
6409 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6410 alc882_capture_mixer },
6411 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6412 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6413 .dac_nids = alc882_dac_nids,
6414 .dig_out_nid = ALC882_DIGOUT_NID,
6415 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6416 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006417 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006418 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6419 .channel_mode = alc882_3ST_6ch_modes,
6420 .need_dac_fix = 1,
6421 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006422 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006423 [ALC882_ASUS_A7M] = {
6424 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6425 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6426 alc880_gpio1_init_verbs,
6427 alc882_asus_a7m_verbs },
6428 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6429 .dac_nids = alc882_dac_nids,
6430 .dig_out_nid = ALC882_DIGOUT_NID,
6431 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6432 .channel_mode = alc880_threestack_modes,
6433 .need_dac_fix = 1,
6434 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006435 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006436};
6437
6438
6439/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006440 * Pin config fixes
6441 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006442enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006443 PINFIX_ABIT_AW9D_MAX
6444};
6445
6446static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6447 { 0x15, 0x01080104 }, /* side */
6448 { 0x16, 0x01011012 }, /* rear */
6449 { 0x17, 0x01016011 }, /* clfe */
6450 { }
6451};
6452
6453static const struct alc_pincfg *alc882_pin_fixes[] = {
6454 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6455};
6456
6457static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6458 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6459 {}
6460};
6461
6462/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006463 * BIOS auto configuration
6464 */
6465static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6466 hda_nid_t nid, int pin_type,
6467 int dac_idx)
6468{
6469 /* set as output */
6470 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006471 int idx;
6472
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006473 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006474 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6475 idx = 4;
6476 else
6477 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006478 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6479
6480}
6481
6482static void alc882_auto_init_multi_out(struct hda_codec *codec)
6483{
6484 struct alc_spec *spec = codec->spec;
6485 int i;
6486
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006487 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006488 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006489 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006490 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006491 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006492 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006493 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006494 }
6495}
6496
6497static void alc882_auto_init_hp_out(struct hda_codec *codec)
6498{
6499 struct alc_spec *spec = codec->spec;
6500 hda_nid_t pin;
6501
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006502 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006503 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006504 /* use dac 0 */
6505 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006506 pin = spec->autocfg.speaker_pins[0];
6507 if (pin)
6508 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006509}
6510
6511#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6512#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6513
6514static void alc882_auto_init_analog_input(struct hda_codec *codec)
6515{
6516 struct alc_spec *spec = codec->spec;
6517 int i;
6518
6519 for (i = 0; i < AUTO_PIN_LAST; i++) {
6520 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006521 unsigned int vref;
6522 if (!nid)
6523 continue;
6524 vref = PIN_IN;
6525 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006526 unsigned int pincap;
6527 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6528 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006529 AC_PINCAP_VREF_80)
6530 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006531 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006532 snd_hda_codec_write(codec, nid, 0,
6533 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6534 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6535 snd_hda_codec_write(codec, nid, 0,
6536 AC_VERB_SET_AMP_GAIN_MUTE,
6537 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006538 }
6539}
6540
Takashi Iwaif511b012008-08-15 16:46:42 +02006541static void alc882_auto_init_input_src(struct hda_codec *codec)
6542{
6543 struct alc_spec *spec = codec->spec;
6544 const struct hda_input_mux *imux = spec->input_mux;
6545 int c;
6546
6547 for (c = 0; c < spec->num_adc_nids; c++) {
6548 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6549 hda_nid_t nid = spec->capsrc_nids[c];
6550 int conns, mute, idx, item;
6551
6552 conns = snd_hda_get_connections(codec, nid, conn_list,
6553 ARRAY_SIZE(conn_list));
6554 if (conns < 0)
6555 continue;
6556 for (idx = 0; idx < conns; idx++) {
6557 /* if the current connection is the selected one,
6558 * unmute it as default - otherwise mute it
6559 */
6560 mute = AMP_IN_MUTE(idx);
6561 for (item = 0; item < imux->num_items; item++) {
6562 if (imux->items[item].index == idx) {
6563 if (spec->cur_mux[c] == item)
6564 mute = AMP_IN_UNMUTE(idx);
6565 break;
6566 }
6567 }
6568 snd_hda_codec_write(codec, nid, 0,
6569 AC_VERB_SET_AMP_GAIN_MUTE, mute);
6570 }
6571 }
6572}
6573
Takashi Iwai776e1842007-08-29 15:07:11 +02006574/* add mic boosts if needed */
6575static int alc_auto_add_mic_boost(struct hda_codec *codec)
6576{
6577 struct alc_spec *spec = codec->spec;
6578 int err;
6579 hda_nid_t nid;
6580
6581 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006582 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006583 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6584 "Mic Boost",
6585 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6586 if (err < 0)
6587 return err;
6588 }
6589 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006590 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006591 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6592 "Front Mic Boost",
6593 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6594 if (err < 0)
6595 return err;
6596 }
6597 return 0;
6598}
6599
Kailang Yangdf694da2005-12-05 19:42:22 +01006600/* almost identical with ALC880 parser... */
6601static int alc882_parse_auto_config(struct hda_codec *codec)
6602{
6603 struct alc_spec *spec = codec->spec;
6604 int err = alc880_parse_auto_config(codec);
6605
6606 if (err < 0)
6607 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006608 else if (!err)
6609 return 0; /* no config found */
6610
6611 err = alc_auto_add_mic_boost(codec);
6612 if (err < 0)
6613 return err;
6614
6615 /* hack - override the init verbs */
6616 spec->init_verbs[0] = alc882_auto_init_verbs;
6617
6618 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006619}
6620
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006621/* additional initialization for auto-configuration model */
6622static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006623{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006624 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006625 alc882_auto_init_multi_out(codec);
6626 alc882_auto_init_hp_out(codec);
6627 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02006628 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006629 if (spec->unsol_event)
6630 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006631}
6632
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006633static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6634
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635static int patch_alc882(struct hda_codec *codec)
6636{
6637 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006638 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006639
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006640 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641 if (spec == NULL)
6642 return -ENOMEM;
6643
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644 codec->spec = spec;
6645
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006646 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6647 alc882_models,
6648 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649
Kailang Yangdf694da2005-12-05 19:42:22 +01006650 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006651 /* Pick up systems that don't supply PCI SSID */
6652 switch (codec->subsystem_id) {
6653 case 0x106b0c00: /* Mac Pro */
6654 board_config = ALC885_MACPRO;
6655 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006656 case 0x106b1000: /* iMac 24 */
6657 board_config = ALC885_IMAC24;
6658 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02006659 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006660 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02006661 case 0x106b3600: /* Macbook 3.1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006662 board_config = ALC885_MBP3;
6663 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006664 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006665 /* ALC889A is handled better as ALC888-compatible */
6666 if (codec->revision_id == 0x100103) {
6667 alc_free(codec);
6668 return patch_alc883(codec);
6669 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006670 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6671 "trying auto-probe from BIOS...\n");
6672 board_config = ALC882_AUTO;
6673 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006674 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006675
Takashi Iwaif95474e2007-07-10 00:47:43 +02006676 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6677
Kailang Yangdf694da2005-12-05 19:42:22 +01006678 if (board_config == ALC882_AUTO) {
6679 /* automatic parse from the BIOS config */
6680 err = alc882_parse_auto_config(codec);
6681 if (err < 0) {
6682 alc_free(codec);
6683 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006684 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006685 printk(KERN_INFO
6686 "hda_codec: Cannot set up configuration "
6687 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006688 board_config = ALC882_3ST_DIG;
6689 }
6690 }
6691
6692 if (board_config != ALC882_AUTO)
6693 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694
Kailang Yang2f893282008-05-27 12:14:47 +02006695 if (codec->vendor_id == 0x10ec0885) {
6696 spec->stream_name_analog = "ALC885 Analog";
6697 spec->stream_name_digital = "ALC885 Digital";
6698 } else {
6699 spec->stream_name_analog = "ALC882 Analog";
6700 spec->stream_name_digital = "ALC882 Digital";
6701 }
6702
Kailang Yangdf694da2005-12-05 19:42:22 +01006703 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6704 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006705 /* FIXME: setup DAC5 */
6706 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6707 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708
Kailang Yangdf694da2005-12-05 19:42:22 +01006709 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6710 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006711
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006712 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006713 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006714 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006715 /* get type */
6716 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006717 if (wcap != AC_WID_AUD_IN) {
6718 spec->adc_nids = alc882_adc_nids_alt;
6719 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006720 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006721 spec->mixers[spec->num_mixers] =
6722 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006723 spec->num_mixers++;
6724 } else {
6725 spec->adc_nids = alc882_adc_nids;
6726 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006727 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006728 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6729 spec->num_mixers++;
6730 }
6731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006732
Takashi Iwai2134ea42008-01-10 16:53:55 +01006733 spec->vmaster_nid = 0x0c;
6734
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006736 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006737 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006738#ifdef CONFIG_SND_HDA_POWER_SAVE
6739 if (!spec->loopback.amplist)
6740 spec->loopback.amplist = alc882_loopbacks;
6741#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742
6743 return 0;
6744}
6745
6746/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006747 * ALC883 support
6748 *
6749 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6750 * configuration. Each pin widget can choose any input DACs and a mixer.
6751 * Each ADC is connected from a mixer of all inputs. This makes possible
6752 * 6-channel independent captures.
6753 *
6754 * In addition, an independent DAC for the multi-playback (not used in this
6755 * driver yet).
6756 */
6757#define ALC883_DIGOUT_NID 0x06
6758#define ALC883_DIGIN_NID 0x0a
6759
6760static hda_nid_t alc883_dac_nids[4] = {
6761 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006762 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006763};
6764
6765static hda_nid_t alc883_adc_nids[2] = {
6766 /* ADC1-2 */
6767 0x08, 0x09,
6768};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006769
Takashi Iwaie1406342008-02-11 18:32:32 +01006770static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6771
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006772/* input MUX */
6773/* FIXME: should be a matrix-type input source selection */
6774
6775static struct hda_input_mux alc883_capture_source = {
6776 .num_items = 4,
6777 .items = {
6778 { "Mic", 0x0 },
6779 { "Front Mic", 0x1 },
6780 { "Line", 0x2 },
6781 { "CD", 0x4 },
6782 },
6783};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006784
Jiang zhe17bba1b2008-06-04 12:11:07 +02006785static struct hda_input_mux alc883_3stack_6ch_intel = {
6786 .num_items = 4,
6787 .items = {
6788 { "Mic", 0x1 },
6789 { "Front Mic", 0x0 },
6790 { "Line", 0x2 },
6791 { "CD", 0x4 },
6792 },
6793};
6794
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006795static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6796 .num_items = 2,
6797 .items = {
6798 { "Mic", 0x1 },
6799 { "Line", 0x2 },
6800 },
6801};
6802
Kailang Yang272a5272007-05-14 11:00:38 +02006803static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6804 .num_items = 4,
6805 .items = {
6806 { "Mic", 0x0 },
6807 { "iMic", 0x1 },
6808 { "Line", 0x2 },
6809 { "CD", 0x4 },
6810 },
6811};
6812
Jiang zhefb97dc62008-03-06 11:07:11 +01006813static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6814 .num_items = 2,
6815 .items = {
6816 { "Mic", 0x0 },
6817 { "Int Mic", 0x1 },
6818 },
6819};
6820
Kailang Yange2757d52008-08-26 13:17:46 +02006821static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6822 .num_items = 3,
6823 .items = {
6824 { "Mic", 0x0 },
6825 { "Front Mic", 0x1 },
6826 { "Line", 0x4 },
6827 },
6828};
6829
6830static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6831 .num_items = 2,
6832 .items = {
6833 { "Mic", 0x0 },
6834 { "Line", 0x2 },
6835 },
6836};
6837
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006838#define alc883_mux_enum_info alc_mux_enum_info
6839#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006840/* ALC883 has the ALC882-type input selection */
6841#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006842
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006843/*
6844 * 2ch mode
6845 */
6846static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6847 { 2, NULL }
6848};
6849
6850/*
6851 * 2ch mode
6852 */
6853static struct hda_verb alc883_3ST_ch2_init[] = {
6854 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6855 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6856 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6857 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6858 { } /* end */
6859};
6860
6861/*
Tobin Davisb2011312007-09-17 12:45:11 +02006862 * 4ch mode
6863 */
6864static struct hda_verb alc883_3ST_ch4_init[] = {
6865 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6866 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6867 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6868 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6869 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6870 { } /* end */
6871};
6872
6873/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006874 * 6ch mode
6875 */
6876static struct hda_verb alc883_3ST_ch6_init[] = {
6877 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6878 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6879 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6880 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6881 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6882 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6883 { } /* end */
6884};
6885
Tobin Davisb2011312007-09-17 12:45:11 +02006886static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006887 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006888 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006889 { 6, alc883_3ST_ch6_init },
6890};
6891
6892/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02006893 * 2ch mode
6894 */
6895static struct hda_verb alc883_3ST_ch2_intel_init[] = {
6896 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6897 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6898 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6899 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6900 { } /* end */
6901};
6902
6903/*
6904 * 4ch mode
6905 */
6906static struct hda_verb alc883_3ST_ch4_intel_init[] = {
6907 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6908 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6909 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6910 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6911 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6912 { } /* end */
6913};
6914
6915/*
6916 * 6ch mode
6917 */
6918static struct hda_verb alc883_3ST_ch6_intel_init[] = {
6919 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6920 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6921 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
6922 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6923 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6924 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6925 { } /* end */
6926};
6927
6928static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
6929 { 2, alc883_3ST_ch2_intel_init },
6930 { 4, alc883_3ST_ch4_intel_init },
6931 { 6, alc883_3ST_ch6_intel_init },
6932};
6933
6934/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006935 * 6ch mode
6936 */
6937static struct hda_verb alc883_sixstack_ch6_init[] = {
6938 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6939 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6940 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6941 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6942 { } /* end */
6943};
6944
6945/*
6946 * 8ch mode
6947 */
6948static struct hda_verb alc883_sixstack_ch8_init[] = {
6949 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6950 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6951 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6952 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6953 { } /* end */
6954};
6955
6956static struct hda_channel_mode alc883_sixstack_modes[2] = {
6957 { 6, alc883_sixstack_ch6_init },
6958 { 8, alc883_sixstack_ch8_init },
6959};
6960
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006961static struct hda_verb alc883_medion_eapd_verbs[] = {
6962 /* eanable EAPD on medion laptop */
6963 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6964 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6965 { }
6966};
6967
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006968/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6969 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6970 */
6971
6972static struct snd_kcontrol_new alc883_base_mixer[] = {
6973 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6974 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6975 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6976 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6977 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6978 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6979 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6980 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6981 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6982 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6983 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6984 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6985 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6986 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6987 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006989 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006990 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6991 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006992 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006993 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6994 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6995 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6996 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6997 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6998 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6999 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7000 {
7001 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7002 /* .name = "Capture Source", */
7003 .name = "Input Source",
7004 .count = 2,
7005 .info = alc883_mux_enum_info,
7006 .get = alc883_mux_enum_get,
7007 .put = alc883_mux_enum_put,
7008 },
7009 { } /* end */
7010};
7011
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007012static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7013 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7014 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7015 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7016 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7017 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7018 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7019 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7020 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7021 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7022 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7023 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7024 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7025 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7026 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7027 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7028 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7029 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7030 {
7031 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7032 /* .name = "Capture Source", */
7033 .name = "Input Source",
7034 .count = 2,
7035 .info = alc883_mux_enum_info,
7036 .get = alc883_mux_enum_get,
7037 .put = alc883_mux_enum_put,
7038 },
7039 { } /* end */
7040};
7041
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007042static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007043 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7044 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7045 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7046 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7047 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7048 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7049 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7050 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7051 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7052 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7053 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7054 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7055 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7056 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7057 {
7058 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7059 /* .name = "Capture Source", */
7060 .name = "Input Source",
7061 .count = 2,
7062 .info = alc883_mux_enum_info,
7063 .get = alc883_mux_enum_get,
7064 .put = alc883_mux_enum_put,
7065 },
7066 { } /* end */
7067};
7068
Jiang zhefb97dc62008-03-06 11:07:11 +01007069static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7070 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7071 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7072 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7073 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7074 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7075 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7076 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7077 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7078 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7079 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7080 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7081 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7082 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7083 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7084 {
7085 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7086 /* .name = "Capture Source", */
7087 .name = "Input Source",
7088 .count = 2,
7089 .info = alc883_mux_enum_info,
7090 .get = alc883_mux_enum_get,
7091 .put = alc883_mux_enum_put,
7092 },
7093 { } /* end */
7094};
7095
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007096static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7097 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7098 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7099 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7100 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7101 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7102 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7103 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7104 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007105 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007106 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7107 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007108 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007109 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7110 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7111 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7112 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7113 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7114 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7115 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7116 {
7117 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7118 /* .name = "Capture Source", */
7119 .name = "Input Source",
7120 .count = 2,
7121 .info = alc883_mux_enum_info,
7122 .get = alc883_mux_enum_get,
7123 .put = alc883_mux_enum_put,
7124 },
7125 { } /* end */
7126};
7127
7128static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7129 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7130 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7131 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7132 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7133 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7134 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7135 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7136 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7137 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7138 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7139 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7140 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7141 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7142 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007143 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007144 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7145 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007146 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007147 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7148 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7149 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7150 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7151 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007152 {
7153 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7154 /* .name = "Capture Source", */
7155 .name = "Input Source",
Kailang Yange2757d52008-08-26 13:17:46 +02007156 .count = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007157 .info = alc883_mux_enum_info,
7158 .get = alc883_mux_enum_get,
7159 .put = alc883_mux_enum_put,
7160 },
7161 { } /* end */
7162};
7163
Jiang zhe17bba1b2008-06-04 12:11:07 +02007164static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7165 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7166 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7167 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7168 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7169 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7170 HDA_OUTPUT),
7171 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7172 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7173 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7174 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7175 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7176 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7177 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7178 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7179 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7180 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7181 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7182 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7183 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7184 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7185 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7186 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7187 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7188 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7189 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7190 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7191 {
7192 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7193 /* .name = "Capture Source", */
7194 .name = "Input Source",
7195 .count = 2,
7196 .info = alc883_mux_enum_info,
7197 .get = alc883_mux_enum_get,
7198 .put = alc883_mux_enum_put,
7199 },
7200 { } /* end */
7201};
7202
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007203static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007204 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007205 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007206 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007207 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007208 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7209 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007210 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7211 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007212 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7213 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7214 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7215 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7216 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7217 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007218 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7220 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007221 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007222 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7223 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7224 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7225 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7226 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7227
7228 {
7229 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7230 /* .name = "Capture Source", */
7231 .name = "Input Source",
7232 .count = 1,
7233 .info = alc883_mux_enum_info,
7234 .get = alc883_mux_enum_get,
7235 .put = alc883_mux_enum_put,
7236 },
7237 { } /* end */
7238};
7239
Kailang Yangccc656c2006-10-17 12:32:26 +02007240static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7241 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7242 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7243 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7244 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7245 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7246 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7247 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7248 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7249 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7250 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7251 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7252 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7253 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7254 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007255 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007256 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7257 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7258 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7259 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7260 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7261 {
7262 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7263 /* .name = "Capture Source", */
7264 .name = "Input Source",
7265 .count = 2,
7266 .info = alc883_mux_enum_info,
7267 .get = alc883_mux_enum_get,
7268 .put = alc883_mux_enum_put,
7269 },
7270 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007271};
Kailang Yangccc656c2006-10-17 12:32:26 +02007272
7273static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7274 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7275 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7276 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7277 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7278 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7279 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007280 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007281 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007282 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7283 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7284 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007285 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7286 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7287 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7288 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7289 {
7290 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7291 /* .name = "Capture Source", */
7292 .name = "Input Source",
7293 .count = 2,
7294 .info = alc883_mux_enum_info,
7295 .get = alc883_mux_enum_get,
7296 .put = alc883_mux_enum_put,
7297 },
7298 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007299};
Kailang Yangccc656c2006-10-17 12:32:26 +02007300
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007301static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7302 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7303 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007304 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7305 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007306 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7307 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7308 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7309 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7310 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7311 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7312 {
7313 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7314 /* .name = "Capture Source", */
7315 .name = "Input Source",
7316 .count = 1,
7317 .info = alc883_mux_enum_info,
7318 .get = alc883_mux_enum_get,
7319 .put = alc883_mux_enum_put,
7320 },
7321 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007322};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007323
Kailang Yang272a5272007-05-14 11:00:38 +02007324static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7325 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7326 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7327 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7328 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7329 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7330 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7331 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7332 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7333 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7334 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7335 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7336 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7337 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7338 {
7339 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7340 /* .name = "Capture Source", */
7341 .name = "Input Source",
7342 .count = 2,
7343 .info = alc883_mux_enum_info,
7344 .get = alc883_mux_enum_get,
7345 .put = alc883_mux_enum_put,
7346 },
7347 { } /* end */
7348};
7349
7350static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7351 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7352 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7353 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7354 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7355 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7356 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7357 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7358 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7359 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7360 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7361 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7362 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7363 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7364 {
7365 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7366 /* .name = "Capture Source", */
7367 .name = "Input Source",
7368 .count = 2,
7369 .info = alc883_mux_enum_info,
7370 .get = alc883_mux_enum_get,
7371 .put = alc883_mux_enum_put,
7372 },
7373 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007374};
Kailang Yang272a5272007-05-14 11:00:38 +02007375
Tobin Davis2880a862007-08-07 11:50:26 +02007376static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007377 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7378 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007379 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007380 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7381 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007382 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7383 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7384 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007385 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7386 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7387 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7388 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7389 {
7390 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7391 /* .name = "Capture Source", */
7392 .name = "Input Source",
7393 .count = 2,
7394 .info = alc883_mux_enum_info,
7395 .get = alc883_mux_enum_get,
7396 .put = alc883_mux_enum_put,
7397 },
7398 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007399};
Tobin Davis2880a862007-08-07 11:50:26 +02007400
Kailang Yange2757d52008-08-26 13:17:46 +02007401static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7402 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7403 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7404 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7405 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7406 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7407 0x0d, 1, 0x0, HDA_OUTPUT),
7408 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7409 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7410 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7411 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7412 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7413 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7414 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7415 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7416 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7417 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7418 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7419 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7420 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7421 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7422 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7423 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7424 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7425 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7426 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7427 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7428 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7429 {
7430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7431 /* .name = "Capture Source", */
7432 .name = "Input Source",
7433 .count = 2,
7434 .info = alc883_mux_enum_info,
7435 .get = alc883_mux_enum_get,
7436 .put = alc883_mux_enum_put,
7437 },
7438 { } /* end */
7439};
7440
7441static struct hda_bind_ctls alc883_bind_cap_vol = {
7442 .ops = &snd_hda_bind_vol,
7443 .values = {
7444 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7445 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7446 0
7447 },
7448};
7449
7450static struct hda_bind_ctls alc883_bind_cap_switch = {
7451 .ops = &snd_hda_bind_sw,
7452 .values = {
7453 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7454 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7455 0
7456 },
7457};
7458
7459static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7460 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7461 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7462 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7463 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7464 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7465 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7466 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7467 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7468 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7469 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7470 {
7471 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7472 /* .name = "Capture Source", */
7473 .name = "Input Source",
7474 .count = 1,
7475 .info = alc883_mux_enum_info,
7476 .get = alc883_mux_enum_get,
7477 .put = alc883_mux_enum_put,
7478 },
7479 { } /* end */
7480};
7481
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007482static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7483 {
7484 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7485 .name = "Channel Mode",
7486 .info = alc_ch_mode_info,
7487 .get = alc_ch_mode_get,
7488 .put = alc_ch_mode_put,
7489 },
7490 { } /* end */
7491};
7492
7493static struct hda_verb alc883_init_verbs[] = {
7494 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007495 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007496 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7497 /* ADC2: mute amp left and right */
7498 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7499 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7500 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7501 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7502 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7504 /* Rear mixer */
7505 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7506 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7507 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7508 /* CLFE mixer */
7509 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7510 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7512 /* Side mixer */
7513 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7514 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7515 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7516
Takashi Iwaicb53c622007-08-10 17:21:45 +02007517 /* mute analog input loopbacks */
7518 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7519 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7520 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7521 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7522 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007523
7524 /* Front Pin: output 0 (0x0c) */
7525 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7526 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7527 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7528 /* Rear Pin: output 1 (0x0d) */
7529 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7530 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7531 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7532 /* CLFE Pin: output 2 (0x0e) */
7533 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7534 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7535 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7536 /* Side Pin: output 3 (0x0f) */
7537 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7538 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7539 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7540 /* Mic (rear) pin: input vref at 80% */
7541 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7542 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7543 /* Front Mic pin: input vref at 80% */
7544 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7545 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7546 /* Line In pin: input */
7547 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7548 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7549 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7550 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7551 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7552 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7553 /* CD pin widget for input */
7554 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7555
7556 /* FIXME: use matrix-type input source selection */
7557 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7558 /* Input mixer2 */
7559 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007560 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7561 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7562 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007563 /* Input mixer3 */
7564 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007565 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7566 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7567 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007568 { }
7569};
7570
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007571/* toggle speaker-output according to the hp-jack state */
7572static void alc883_mitac_hp_automute(struct hda_codec *codec)
7573{
7574 unsigned int present;
7575
7576 present = snd_hda_codec_read(codec, 0x15, 0,
7577 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7578 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7579 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7580 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7581 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7582}
7583
7584/* auto-toggle front mic */
7585/*
7586static void alc883_mitac_mic_automute(struct hda_codec *codec)
7587{
7588 unsigned int present;
7589 unsigned char bits;
7590
7591 present = snd_hda_codec_read(codec, 0x18, 0,
7592 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7593 bits = present ? HDA_AMP_MUTE : 0;
7594 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7595}
7596*/
7597
7598static void alc883_mitac_automute(struct hda_codec *codec)
7599{
7600 alc883_mitac_hp_automute(codec);
7601 /* alc883_mitac_mic_automute(codec); */
7602}
7603
7604static void alc883_mitac_unsol_event(struct hda_codec *codec,
7605 unsigned int res)
7606{
7607 switch (res >> 26) {
7608 case ALC880_HP_EVENT:
7609 alc883_mitac_hp_automute(codec);
7610 break;
7611 case ALC880_MIC_EVENT:
7612 /* alc883_mitac_mic_automute(codec); */
7613 break;
7614 }
7615}
7616
7617static struct hda_verb alc883_mitac_verbs[] = {
7618 /* HP */
7619 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7620 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7621 /* Subwoofer */
7622 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7623 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7624
7625 /* enable unsolicited event */
7626 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7627 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7628
7629 { } /* end */
7630};
7631
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007632static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007633 /* HP */
7634 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7635 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7636 /* Int speaker */
7637 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7638 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7639
7640 /* enable unsolicited event */
7641 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007642 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007643
7644 { } /* end */
7645};
7646
Jiang zhefb97dc62008-03-06 11:07:11 +01007647static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7648 /* HP */
7649 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7650 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7651 /* Subwoofer */
7652 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7653 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7654
7655 /* enable unsolicited event */
7656 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7657
7658 { } /* end */
7659};
7660
Kailang Yangccc656c2006-10-17 12:32:26 +02007661static struct hda_verb alc883_tagra_verbs[] = {
7662 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7663 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7664
7665 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7666 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007667
Kailang Yangccc656c2006-10-17 12:32:26 +02007668 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7669 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7670 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7671
7672 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007673 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7674 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7675 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007676
7677 { } /* end */
7678};
7679
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007680static struct hda_verb alc883_lenovo_101e_verbs[] = {
7681 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7682 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7683 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7684 { } /* end */
7685};
7686
Kailang Yang272a5272007-05-14 11:00:38 +02007687static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7688 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7689 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7690 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7691 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7692 { } /* end */
7693};
7694
7695static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7696 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7697 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7698 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7699 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7700 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7701 { } /* end */
7702};
7703
Kailang Yang189609a2007-08-20 11:31:23 +02007704static struct hda_verb alc883_haier_w66_verbs[] = {
7705 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7706 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7707
7708 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7709
7710 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7711 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7712 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7713 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7714 { } /* end */
7715};
7716
Kailang Yange2757d52008-08-26 13:17:46 +02007717static struct hda_verb alc888_lenovo_sky_verbs[] = {
7718 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7719 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7720 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7721 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7722 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7723 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7724 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7725 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7726 { } /* end */
7727};
7728
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007729static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007730 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007731 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7732 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007733 { }
7734};
7735
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007736static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007737 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7738 { }
7739};
7740
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007741static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007742 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7743 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7744 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7745 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7746 { }
7747};
7748
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007749static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007750 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7751 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7752 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7753 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7754 { }
7755};
7756
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007757static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7758 { 2, alc888_3st_hp_2ch_init },
7759 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007760};
7761
Kailang Yang272a5272007-05-14 11:00:38 +02007762/* toggle front-jack and RCA according to the hp-jack state */
7763static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7764{
7765 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007766
Kailang Yang272a5272007-05-14 11:00:38 +02007767 present = snd_hda_codec_read(codec, 0x1b, 0,
7768 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007769 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7770 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7771 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7772 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007773}
7774
7775/* toggle RCA according to the front-jack state */
7776static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7777{
7778 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007779
Kailang Yang272a5272007-05-14 11:00:38 +02007780 present = snd_hda_codec_read(codec, 0x14, 0,
7781 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007782 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7783 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007784}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007785
Kailang Yang272a5272007-05-14 11:00:38 +02007786static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7787 unsigned int res)
7788{
7789 if ((res >> 26) == ALC880_HP_EVENT)
7790 alc888_lenovo_ms7195_front_automute(codec);
7791 if ((res >> 26) == ALC880_FRONT_EVENT)
7792 alc888_lenovo_ms7195_rca_automute(codec);
7793}
7794
7795static struct hda_verb alc883_medion_md2_verbs[] = {
7796 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7797 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7798
7799 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7800
7801 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7802 { } /* end */
7803};
7804
7805/* toggle speaker-output according to the hp-jack state */
7806static void alc883_medion_md2_automute(struct hda_codec *codec)
7807{
7808 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007809
Kailang Yang272a5272007-05-14 11:00:38 +02007810 present = snd_hda_codec_read(codec, 0x14, 0,
7811 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007812 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7813 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007814}
7815
7816static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7817 unsigned int res)
7818{
7819 if ((res >> 26) == ALC880_HP_EVENT)
7820 alc883_medion_md2_automute(codec);
7821}
7822
Kailang Yangccc656c2006-10-17 12:32:26 +02007823/* toggle speaker-output according to the hp-jack state */
7824static void alc883_tagra_automute(struct hda_codec *codec)
7825{
7826 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007827 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007828
7829 present = snd_hda_codec_read(codec, 0x14, 0,
7830 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007831 bits = present ? HDA_AMP_MUTE : 0;
7832 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7833 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007834 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7835 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007836}
7837
7838static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7839{
7840 if ((res >> 26) == ALC880_HP_EVENT)
7841 alc883_tagra_automute(codec);
7842}
7843
Jiang zhe368c7a92008-03-04 11:20:33 +01007844/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007845static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007846{
7847 unsigned int present;
7848 unsigned char bits;
7849
7850 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7851 & AC_PINSENSE_PRESENCE;
7852 bits = present ? HDA_AMP_MUTE : 0;
7853 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7854 HDA_AMP_MUTE, bits);
7855}
7856
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007857static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7858{
7859 unsigned int present;
7860
7861 present = snd_hda_codec_read(codec, 0x18, 0,
7862 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7863 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7864 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7865}
7866
7867static void alc883_clevo_m720_automute(struct hda_codec *codec)
7868{
7869 alc883_clevo_m720_hp_automute(codec);
7870 alc883_clevo_m720_mic_automute(codec);
7871}
7872
7873static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007874 unsigned int res)
7875{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007876 switch (res >> 26) {
7877 case ALC880_HP_EVENT:
7878 alc883_clevo_m720_hp_automute(codec);
7879 break;
7880 case ALC880_MIC_EVENT:
7881 alc883_clevo_m720_mic_automute(codec);
7882 break;
7883 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007884}
7885
Jiang zhefb97dc62008-03-06 11:07:11 +01007886/* toggle speaker-output according to the hp-jack state */
7887static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7888{
7889 unsigned int present;
7890 unsigned char bits;
7891
7892 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7893 & AC_PINSENSE_PRESENCE;
7894 bits = present ? HDA_AMP_MUTE : 0;
7895 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7896 HDA_AMP_MUTE, bits);
7897}
7898
7899static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7900 unsigned int res)
7901{
7902 if ((res >> 26) == ALC880_HP_EVENT)
7903 alc883_2ch_fujitsu_pi2515_automute(codec);
7904}
7905
Kailang Yang189609a2007-08-20 11:31:23 +02007906static void alc883_haier_w66_automute(struct hda_codec *codec)
7907{
7908 unsigned int present;
7909 unsigned char bits;
7910
7911 present = snd_hda_codec_read(codec, 0x1b, 0,
7912 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7913 bits = present ? 0x80 : 0;
7914 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7915 0x80, bits);
7916}
7917
7918static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7919 unsigned int res)
7920{
7921 if ((res >> 26) == ALC880_HP_EVENT)
7922 alc883_haier_w66_automute(codec);
7923}
7924
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007925static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7926{
7927 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007928 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007929
7930 present = snd_hda_codec_read(codec, 0x14, 0,
7931 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007932 bits = present ? HDA_AMP_MUTE : 0;
7933 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7934 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007935}
7936
7937static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7938{
7939 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007940 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007941
7942 present = snd_hda_codec_read(codec, 0x1b, 0,
7943 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007944 bits = present ? HDA_AMP_MUTE : 0;
7945 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7946 HDA_AMP_MUTE, bits);
7947 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7948 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007949}
7950
7951static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7952 unsigned int res)
7953{
7954 if ((res >> 26) == ALC880_HP_EVENT)
7955 alc883_lenovo_101e_all_automute(codec);
7956 if ((res >> 26) == ALC880_FRONT_EVENT)
7957 alc883_lenovo_101e_ispeaker_automute(codec);
7958}
7959
Takashi Iwai676a9b52007-08-16 15:23:35 +02007960/* toggle speaker-output according to the hp-jack state */
7961static void alc883_acer_aspire_automute(struct hda_codec *codec)
7962{
7963 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007964
Takashi Iwai676a9b52007-08-16 15:23:35 +02007965 present = snd_hda_codec_read(codec, 0x14, 0,
7966 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7967 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7968 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7969 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7970 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7971}
7972
7973static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7974 unsigned int res)
7975{
7976 if ((res >> 26) == ALC880_HP_EVENT)
7977 alc883_acer_aspire_automute(codec);
7978}
7979
Kailang Yangd1a991a2007-08-15 16:21:59 +02007980static struct hda_verb alc883_acer_eapd_verbs[] = {
7981 /* HP Pin: output 0 (0x0c) */
7982 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7983 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7984 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7985 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007986 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7987 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007988 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007989 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7990 /* eanable EAPD on medion laptop */
7991 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7992 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007993 /* enable unsolicited event */
7994 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007995 { }
7996};
7997
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007998static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7999{
8000 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008001
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008002 present = snd_hda_codec_read(codec, 0x1b, 0,
8003 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8004 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8005 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8006 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8007 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8008 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8009 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8010 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8011 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8012}
8013
8014static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
8015 unsigned int res)
8016{
8017 switch (res >> 26) {
8018 case ALC880_HP_EVENT:
8019 printk("hp_event\n");
8020 alc888_6st_dell_front_automute(codec);
8021 break;
8022 }
8023}
8024
Kailang Yange2757d52008-08-26 13:17:46 +02008025static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
8026{
8027 unsigned int mute;
8028 unsigned int present;
8029
8030 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8031 present = snd_hda_codec_read(codec, 0x1b, 0,
8032 AC_VERB_GET_PIN_SENSE, 0);
8033 present = (present & 0x80000000) != 0;
8034 if (present) {
8035 /* mute internal speaker */
8036 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8037 HDA_AMP_MUTE, HDA_AMP_MUTE);
8038 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8039 HDA_AMP_MUTE, HDA_AMP_MUTE);
8040 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8041 HDA_AMP_MUTE, HDA_AMP_MUTE);
8042 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8043 HDA_AMP_MUTE, HDA_AMP_MUTE);
8044 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8045 HDA_AMP_MUTE, HDA_AMP_MUTE);
8046 } else {
8047 /* unmute internal speaker if necessary */
8048 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8049 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8050 HDA_AMP_MUTE, mute);
8051 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8052 HDA_AMP_MUTE, mute);
8053 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8054 HDA_AMP_MUTE, mute);
8055 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8056 HDA_AMP_MUTE, mute);
8057 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8058 HDA_AMP_MUTE, mute);
8059 }
8060}
8061
8062static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
8063 unsigned int res)
8064{
8065 if ((res >> 26) == ALC880_HP_EVENT)
8066 alc888_lenovo_sky_front_automute(codec);
8067}
8068
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008069/*
8070 * generic initialization of ADC, input mixers and output mixers
8071 */
8072static struct hda_verb alc883_auto_init_verbs[] = {
8073 /*
8074 * Unmute ADC0-2 and set the default input to mic-in
8075 */
8076 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8077 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8078 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8079 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8080
Takashi Iwaicb53c622007-08-10 17:21:45 +02008081 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008082 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008083 * Note: PASD motherboards uses the Line In 2 as the input for
8084 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008085 */
8086 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008087 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8088 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8089 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8090 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8091 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008092
8093 /*
8094 * Set up output mixers (0x0c - 0x0f)
8095 */
8096 /* set vol=0 to output mixers */
8097 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8098 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8099 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8100 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8101 /* set up input amps for analog loopback */
8102 /* Amp Indices: DAC = 0, mixer = 1 */
8103 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8104 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8105 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8106 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8107 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8108 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8109 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8110 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8111 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8112 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8113
8114 /* FIXME: use matrix-type input source selection */
8115 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8116 /* Input mixer1 */
8117 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8118 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8119 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008120 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008121 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8122 /* Input mixer2 */
8123 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8124 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8125 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008126 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008127 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008128
8129 { }
8130};
8131
8132/* capture mixer elements */
8133static struct snd_kcontrol_new alc883_capture_mixer[] = {
8134 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
8135 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
8136 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
8137 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
8138 {
8139 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8140 /* The multiple "Capture Source" controls confuse alsamixer
8141 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008142 */
8143 /* .name = "Capture Source", */
8144 .name = "Input Source",
8145 .count = 2,
8146 .info = alc882_mux_enum_info,
8147 .get = alc882_mux_enum_get,
8148 .put = alc882_mux_enum_put,
8149 },
8150 { } /* end */
8151};
8152
Kailang Yange2757d52008-08-26 13:17:46 +02008153static struct hda_verb alc888_asus_m90v_verbs[] = {
8154 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8155 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8156 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8157 /* enable unsolicited event */
8158 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8159 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8160 { } /* end */
8161};
8162
8163static void alc883_nb_mic_automute(struct hda_codec *codec)
8164{
8165 unsigned int present;
8166
8167 present = snd_hda_codec_read(codec, 0x18, 0,
8168 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8169 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8170 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8171 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8172 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8173}
8174
8175static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8176{
8177 unsigned int present;
8178 unsigned char bits;
8179
8180 present = snd_hda_codec_read(codec, 0x1b, 0,
8181 AC_VERB_GET_PIN_SENSE, 0)
8182 & AC_PINSENSE_PRESENCE;
8183 bits = present ? 0 : PIN_OUT;
8184 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8185 bits);
8186 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8187 bits);
8188 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8189 bits);
8190}
8191
8192static void alc883_mode2_unsol_event(struct hda_codec *codec,
8193 unsigned int res)
8194{
8195 switch (res >> 26) {
8196 case ALC880_HP_EVENT:
8197 alc883_M90V_speaker_automute(codec);
8198 break;
8199 case ALC880_MIC_EVENT:
8200 alc883_nb_mic_automute(codec);
8201 break;
8202 }
8203}
8204
8205static void alc883_mode2_inithook(struct hda_codec *codec)
8206{
8207 alc883_M90V_speaker_automute(codec);
8208 alc883_nb_mic_automute(codec);
8209}
8210
8211static struct hda_verb alc888_asus_eee1601_verbs[] = {
8212 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8213 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8214 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8215 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8216 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8217 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8218 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8219 /* enable unsolicited event */
8220 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8221 { } /* end */
8222};
8223
8224static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8225{
8226 unsigned int present;
8227 unsigned char bits;
8228
8229 present = snd_hda_codec_read(codec, 0x14, 0,
8230 AC_VERB_GET_PIN_SENSE, 0)
8231 & AC_PINSENSE_PRESENCE;
8232 bits = present ? 0 : PIN_OUT;
8233 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8234 bits);
8235}
8236
8237static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8238 unsigned int res)
8239{
8240 switch (res >> 26) {
8241 case ALC880_HP_EVENT:
8242 alc883_eee1601_speaker_automute(codec);
8243 break;
8244 }
8245}
8246
8247static void alc883_eee1601_inithook(struct hda_codec *codec)
8248{
8249 alc883_eee1601_speaker_automute(codec);
8250}
8251
Takashi Iwaicb53c622007-08-10 17:21:45 +02008252#ifdef CONFIG_SND_HDA_POWER_SAVE
8253#define alc883_loopbacks alc880_loopbacks
8254#endif
8255
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008256/* pcm configuration: identiacal with ALC880 */
8257#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8258#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008259#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008260#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8261#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8262
8263/*
8264 * configuration and preset
8265 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008266static const char *alc883_models[ALC883_MODEL_LAST] = {
8267 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8268 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8269 [ALC883_3ST_6ch] = "3stack-6ch",
8270 [ALC883_6ST_DIG] = "6stack-dig",
8271 [ALC883_TARGA_DIG] = "targa-dig",
8272 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008273 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008274 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008275 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008276 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008277 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008278 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008279 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8280 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008281 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008282 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008283 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008284 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008285 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008286 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008287 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008288 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008289 [ALC883_AUTO] = "auto",
8290};
8291
8292static struct snd_pci_quirk alc883_cfg_tbl[] = {
8293 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008294 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
8295 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8296 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008297 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008298 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008299 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008300 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008301 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8302 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008303 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008304 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Kailang Yange2757d52008-08-26 13:17:46 +02008305 SND_PCI_QUIRK(0x1043, 0x8317, "Asus M90V", ALC888_ASUS_M90V),
8306 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008307 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008308 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008309 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8310 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008311 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008312 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008313 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008314 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8315 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8316 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008317 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008318 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008319 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008320 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8321 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8322 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8323 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8324 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8325 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8326 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8327 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8328 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008329 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8330 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008331 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008332 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008333 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008334 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008335 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008336 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008337 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8338 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008339 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008340 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008341 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01008342 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02008343 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008344 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008345 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8346 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008347 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008348 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008349 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008350 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008351 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8352 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008353 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008354 {}
8355};
8356
8357static struct alc_config_preset alc883_presets[] = {
8358 [ALC883_3ST_2ch_DIG] = {
8359 .mixers = { alc883_3ST_2ch_mixer },
8360 .init_verbs = { alc883_init_verbs },
8361 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8362 .dac_nids = alc883_dac_nids,
8363 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008364 .dig_in_nid = ALC883_DIGIN_NID,
8365 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8366 .channel_mode = alc883_3ST_2ch_modes,
8367 .input_mux = &alc883_capture_source,
8368 },
8369 [ALC883_3ST_6ch_DIG] = {
8370 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8371 .init_verbs = { alc883_init_verbs },
8372 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8373 .dac_nids = alc883_dac_nids,
8374 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008375 .dig_in_nid = ALC883_DIGIN_NID,
8376 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8377 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008378 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008379 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008380 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008381 [ALC883_3ST_6ch] = {
8382 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8383 .init_verbs = { alc883_init_verbs },
8384 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8385 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008386 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8387 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008388 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008389 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008390 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008391 [ALC883_3ST_6ch_INTEL] = {
8392 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8393 .init_verbs = { alc883_init_verbs },
8394 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8395 .dac_nids = alc883_dac_nids,
8396 .dig_out_nid = ALC883_DIGOUT_NID,
8397 .dig_in_nid = ALC883_DIGIN_NID,
8398 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8399 .channel_mode = alc883_3ST_6ch_intel_modes,
8400 .need_dac_fix = 1,
8401 .input_mux = &alc883_3stack_6ch_intel,
8402 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008403 [ALC883_6ST_DIG] = {
8404 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8405 .init_verbs = { alc883_init_verbs },
8406 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8407 .dac_nids = alc883_dac_nids,
8408 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008409 .dig_in_nid = ALC883_DIGIN_NID,
8410 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8411 .channel_mode = alc883_sixstack_modes,
8412 .input_mux = &alc883_capture_source,
8413 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008414 [ALC883_TARGA_DIG] = {
8415 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8416 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8417 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8418 .dac_nids = alc883_dac_nids,
8419 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008420 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8421 .channel_mode = alc883_3ST_6ch_modes,
8422 .need_dac_fix = 1,
8423 .input_mux = &alc883_capture_source,
8424 .unsol_event = alc883_tagra_unsol_event,
8425 .init_hook = alc883_tagra_automute,
8426 },
8427 [ALC883_TARGA_2ch_DIG] = {
8428 .mixers = { alc883_tagra_2ch_mixer},
8429 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8430 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8431 .dac_nids = alc883_dac_nids,
8432 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008433 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8434 .channel_mode = alc883_3ST_2ch_modes,
8435 .input_mux = &alc883_capture_source,
8436 .unsol_event = alc883_tagra_unsol_event,
8437 .init_hook = alc883_tagra_automute,
8438 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008439 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008440 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008441 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8442 * and the headphone jack. Turn this on and rely on the
8443 * standard mute methods whenever the user wants to turn
8444 * these outputs off.
8445 */
8446 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8447 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8448 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008449 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8450 .channel_mode = alc883_3ST_2ch_modes,
8451 .input_mux = &alc883_capture_source,
8452 },
Tobin Davis2880a862007-08-07 11:50:26 +02008453 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008454 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008455 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008456 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8457 .dac_nids = alc883_dac_nids,
8458 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008459 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8460 .channel_mode = alc883_3ST_2ch_modes,
8461 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008462 .unsol_event = alc883_acer_aspire_unsol_event,
8463 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008464 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008465 [ALC883_MEDION] = {
8466 .mixers = { alc883_fivestack_mixer,
8467 alc883_chmode_mixer },
8468 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008469 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008470 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8471 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02008472 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8473 .channel_mode = alc883_sixstack_modes,
8474 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008475 },
Kailang Yang272a5272007-05-14 11:00:38 +02008476 [ALC883_MEDION_MD2] = {
8477 .mixers = { alc883_medion_md2_mixer},
8478 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8479 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8480 .dac_nids = alc883_dac_nids,
8481 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008482 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8483 .channel_mode = alc883_3ST_2ch_modes,
8484 .input_mux = &alc883_capture_source,
8485 .unsol_event = alc883_medion_md2_unsol_event,
8486 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008487 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008488 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008489 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008490 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8491 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8492 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008493 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8494 .channel_mode = alc883_3ST_2ch_modes,
8495 .input_mux = &alc883_capture_source,
8496 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008497 [ALC883_CLEVO_M720] = {
8498 .mixers = { alc883_clevo_m720_mixer },
8499 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008500 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8501 .dac_nids = alc883_dac_nids,
8502 .dig_out_nid = ALC883_DIGOUT_NID,
8503 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8504 .channel_mode = alc883_3ST_2ch_modes,
8505 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008506 .unsol_event = alc883_clevo_m720_unsol_event,
8507 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008508 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008509 [ALC883_LENOVO_101E_2ch] = {
8510 .mixers = { alc883_lenovo_101e_2ch_mixer},
8511 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8512 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8513 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008514 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8515 .channel_mode = alc883_3ST_2ch_modes,
8516 .input_mux = &alc883_lenovo_101e_capture_source,
8517 .unsol_event = alc883_lenovo_101e_unsol_event,
8518 .init_hook = alc883_lenovo_101e_all_automute,
8519 },
Kailang Yang272a5272007-05-14 11:00:38 +02008520 [ALC883_LENOVO_NB0763] = {
8521 .mixers = { alc883_lenovo_nb0763_mixer },
8522 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8523 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8524 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008525 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8526 .channel_mode = alc883_3ST_2ch_modes,
8527 .need_dac_fix = 1,
8528 .input_mux = &alc883_lenovo_nb0763_capture_source,
8529 .unsol_event = alc883_medion_md2_unsol_event,
8530 .init_hook = alc883_medion_md2_automute,
8531 },
8532 [ALC888_LENOVO_MS7195_DIG] = {
8533 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8534 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8535 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8536 .dac_nids = alc883_dac_nids,
8537 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008538 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8539 .channel_mode = alc883_3ST_6ch_modes,
8540 .need_dac_fix = 1,
8541 .input_mux = &alc883_capture_source,
8542 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8543 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008544 },
8545 [ALC883_HAIER_W66] = {
8546 .mixers = { alc883_tagra_2ch_mixer},
8547 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8548 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8549 .dac_nids = alc883_dac_nids,
8550 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008551 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8552 .channel_mode = alc883_3ST_2ch_modes,
8553 .input_mux = &alc883_capture_source,
8554 .unsol_event = alc883_haier_w66_unsol_event,
8555 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008556 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008557 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008558 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008559 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008560 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8561 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008562 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8563 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008564 .need_dac_fix = 1,
8565 .input_mux = &alc883_capture_source,
8566 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008567 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008568 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008569 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8570 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8571 .dac_nids = alc883_dac_nids,
8572 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008573 .dig_in_nid = ALC883_DIGIN_NID,
8574 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8575 .channel_mode = alc883_sixstack_modes,
8576 .input_mux = &alc883_capture_source,
8577 .unsol_event = alc888_6st_dell_unsol_event,
8578 .init_hook = alc888_6st_dell_front_automute,
8579 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008580 [ALC883_MITAC] = {
8581 .mixers = { alc883_mitac_mixer },
8582 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8583 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8584 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008585 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8586 .channel_mode = alc883_3ST_2ch_modes,
8587 .input_mux = &alc883_capture_source,
8588 .unsol_event = alc883_mitac_unsol_event,
8589 .init_hook = alc883_mitac_automute,
8590 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008591 [ALC883_FUJITSU_PI2515] = {
8592 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8593 .init_verbs = { alc883_init_verbs,
8594 alc883_2ch_fujitsu_pi2515_verbs},
8595 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8596 .dac_nids = alc883_dac_nids,
8597 .dig_out_nid = ALC883_DIGOUT_NID,
8598 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8599 .channel_mode = alc883_3ST_2ch_modes,
8600 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8601 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8602 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8603 },
Kailang Yange2757d52008-08-26 13:17:46 +02008604 [ALC888_LENOVO_SKY] = {
8605 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8606 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8607 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8608 .dac_nids = alc883_dac_nids,
8609 .dig_out_nid = ALC883_DIGOUT_NID,
8610 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
8611 .adc_nids = alc883_adc_nids,
8612 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8613 .channel_mode = alc883_sixstack_modes,
8614 .need_dac_fix = 1,
8615 .input_mux = &alc883_lenovo_sky_capture_source,
8616 .unsol_event = alc883_lenovo_sky_unsol_event,
8617 .init_hook = alc888_lenovo_sky_front_automute,
8618 },
8619 [ALC888_ASUS_M90V] = {
8620 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8621 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8622 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8623 .dac_nids = alc883_dac_nids,
8624 .dig_out_nid = ALC883_DIGOUT_NID,
8625 .dig_in_nid = ALC883_DIGIN_NID,
8626 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8627 .channel_mode = alc883_3ST_6ch_modes,
8628 .need_dac_fix = 1,
8629 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8630 .unsol_event = alc883_mode2_unsol_event,
8631 .init_hook = alc883_mode2_inithook,
8632 },
8633 [ALC888_ASUS_EEE1601] = {
8634 .mixers = { alc883_asus_eee1601_mixer },
8635 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8636 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8637 .dac_nids = alc883_dac_nids,
8638 .dig_out_nid = ALC883_DIGOUT_NID,
8639 .dig_in_nid = ALC883_DIGIN_NID,
8640 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8641 .channel_mode = alc883_3ST_2ch_modes,
8642 .need_dac_fix = 1,
8643 .input_mux = &alc883_asus_eee1601_capture_source,
8644 .unsol_event = alc883_eee1601_unsol_event,
8645 .init_hook = alc883_eee1601_inithook,
8646 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008647};
8648
8649
8650/*
8651 * BIOS auto configuration
8652 */
8653static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8654 hda_nid_t nid, int pin_type,
8655 int dac_idx)
8656{
8657 /* set as output */
8658 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008659 int idx;
8660
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008661 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008662 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8663 idx = 4;
8664 else
8665 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008666 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8667
8668}
8669
8670static void alc883_auto_init_multi_out(struct hda_codec *codec)
8671{
8672 struct alc_spec *spec = codec->spec;
8673 int i;
8674
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008675 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008676 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008677 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008678 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008679 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008680 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008681 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008682 }
8683}
8684
8685static void alc883_auto_init_hp_out(struct hda_codec *codec)
8686{
8687 struct alc_spec *spec = codec->spec;
8688 hda_nid_t pin;
8689
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008690 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008691 if (pin) /* connect to front */
8692 /* use dac 0 */
8693 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008694 pin = spec->autocfg.speaker_pins[0];
8695 if (pin)
8696 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008697}
8698
8699#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8700#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8701
8702static void alc883_auto_init_analog_input(struct hda_codec *codec)
8703{
8704 struct alc_spec *spec = codec->spec;
8705 int i;
8706
8707 for (i = 0; i < AUTO_PIN_LAST; i++) {
8708 hda_nid_t nid = spec->autocfg.input_pins[i];
8709 if (alc883_is_input_pin(nid)) {
8710 snd_hda_codec_write(codec, nid, 0,
8711 AC_VERB_SET_PIN_WIDGET_CONTROL,
8712 (i <= AUTO_PIN_FRONT_MIC ?
8713 PIN_VREF80 : PIN_IN));
8714 if (nid != ALC883_PIN_CD_NID)
8715 snd_hda_codec_write(codec, nid, 0,
8716 AC_VERB_SET_AMP_GAIN_MUTE,
8717 AMP_OUT_MUTE);
8718 }
8719 }
8720}
8721
Takashi Iwaif511b012008-08-15 16:46:42 +02008722#define alc883_auto_init_input_src alc882_auto_init_input_src
8723
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008724/* almost identical with ALC880 parser... */
8725static int alc883_parse_auto_config(struct hda_codec *codec)
8726{
8727 struct alc_spec *spec = codec->spec;
8728 int err = alc880_parse_auto_config(codec);
8729
8730 if (err < 0)
8731 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008732 else if (!err)
8733 return 0; /* no config found */
8734
8735 err = alc_auto_add_mic_boost(codec);
8736 if (err < 0)
8737 return err;
8738
8739 /* hack - override the init verbs */
8740 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008741 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
8742 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02008743
8744 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008745}
8746
8747/* additional initialization for auto-configuration model */
8748static void alc883_auto_init(struct hda_codec *codec)
8749{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008750 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008751 alc883_auto_init_multi_out(codec);
8752 alc883_auto_init_hp_out(codec);
8753 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02008754 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008755 if (spec->unsol_event)
8756 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008757}
8758
8759static int patch_alc883(struct hda_codec *codec)
8760{
8761 struct alc_spec *spec;
8762 int err, board_config;
8763
8764 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8765 if (spec == NULL)
8766 return -ENOMEM;
8767
8768 codec->spec = spec;
8769
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02008770 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
8771
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008772 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8773 alc883_models,
8774 alc883_cfg_tbl);
8775 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008776 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8777 "trying auto-probe from BIOS...\n");
8778 board_config = ALC883_AUTO;
8779 }
8780
8781 if (board_config == ALC883_AUTO) {
8782 /* automatic parse from the BIOS config */
8783 err = alc883_parse_auto_config(codec);
8784 if (err < 0) {
8785 alc_free(codec);
8786 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008787 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008788 printk(KERN_INFO
8789 "hda_codec: Cannot set up configuration "
8790 "from BIOS. Using base mode...\n");
8791 board_config = ALC883_3ST_2ch_DIG;
8792 }
8793 }
8794
8795 if (board_config != ALC883_AUTO)
8796 setup_preset(spec, &alc883_presets[board_config]);
8797
Kailang Yang2f893282008-05-27 12:14:47 +02008798 switch (codec->vendor_id) {
8799 case 0x10ec0888:
8800 spec->stream_name_analog = "ALC888 Analog";
8801 spec->stream_name_digital = "ALC888 Digital";
8802 break;
8803 case 0x10ec0889:
8804 spec->stream_name_analog = "ALC889 Analog";
8805 spec->stream_name_digital = "ALC889 Digital";
8806 break;
8807 default:
8808 spec->stream_name_analog = "ALC883 Analog";
8809 spec->stream_name_digital = "ALC883 Digital";
8810 break;
8811 }
8812
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008813 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8814 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008815 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008816
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008817 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8818 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8819
Takashi Iwaie1406342008-02-11 18:32:32 +01008820 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8821 spec->adc_nids = alc883_adc_nids;
8822 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008823
Takashi Iwai2134ea42008-01-10 16:53:55 +01008824 spec->vmaster_nid = 0x0c;
8825
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008826 codec->patch_ops = alc_patch_ops;
8827 if (board_config == ALC883_AUTO)
8828 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02008829
Takashi Iwaicb53c622007-08-10 17:21:45 +02008830#ifdef CONFIG_SND_HDA_POWER_SAVE
8831 if (!spec->loopback.amplist)
8832 spec->loopback.amplist = alc883_loopbacks;
8833#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008834
8835 return 0;
8836}
8837
8838/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008839 * ALC262 support
8840 */
8841
8842#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8843#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8844
8845#define alc262_dac_nids alc260_dac_nids
8846#define alc262_adc_nids alc882_adc_nids
8847#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008848#define alc262_capsrc_nids alc882_capsrc_nids
8849#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008850
8851#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008852#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008853
Kailang Yang4e555fe2008-08-26 13:05:55 +02008854static hda_nid_t alc262_dmic_adc_nids[1] = {
8855 /* ADC0 */
8856 0x09
8857};
8858
8859static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
8860
Kailang Yangdf694da2005-12-05 19:42:22 +01008861static struct snd_kcontrol_new alc262_base_mixer[] = {
8862 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8863 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8864 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8865 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8866 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8867 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8868 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8869 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008870 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008871 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8872 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008873 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008874 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008875 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008876 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8877 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8878 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8879 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008880 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008881};
8882
Kailang Yangccc656c2006-10-17 12:32:26 +02008883static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8884 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8885 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8886 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8887 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8888 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8889 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8890 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8891 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008892 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008893 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8894 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008895 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008896 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008897 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008898 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8899 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8900 { } /* end */
8901};
8902
Takashi Iwaice875f02008-01-28 18:17:43 +01008903/* update HP, line and mono-out pins according to the master switch */
8904static void alc262_hp_master_update(struct hda_codec *codec)
8905{
8906 struct alc_spec *spec = codec->spec;
8907 int val = spec->master_sw;
8908
8909 /* HP & line-out */
8910 snd_hda_codec_write_cache(codec, 0x1b, 0,
8911 AC_VERB_SET_PIN_WIDGET_CONTROL,
8912 val ? PIN_HP : 0);
8913 snd_hda_codec_write_cache(codec, 0x15, 0,
8914 AC_VERB_SET_PIN_WIDGET_CONTROL,
8915 val ? PIN_HP : 0);
8916 /* mono (speaker) depending on the HP jack sense */
8917 val = val && !spec->jack_present;
8918 snd_hda_codec_write_cache(codec, 0x16, 0,
8919 AC_VERB_SET_PIN_WIDGET_CONTROL,
8920 val ? PIN_OUT : 0);
8921}
8922
8923static void alc262_hp_bpc_automute(struct hda_codec *codec)
8924{
8925 struct alc_spec *spec = codec->spec;
8926 unsigned int presence;
8927 presence = snd_hda_codec_read(codec, 0x1b, 0,
8928 AC_VERB_GET_PIN_SENSE, 0);
8929 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8930 alc262_hp_master_update(codec);
8931}
8932
8933static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8934{
8935 if ((res >> 26) != ALC880_HP_EVENT)
8936 return;
8937 alc262_hp_bpc_automute(codec);
8938}
8939
8940static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8941{
8942 struct alc_spec *spec = codec->spec;
8943 unsigned int presence;
8944 presence = snd_hda_codec_read(codec, 0x15, 0,
8945 AC_VERB_GET_PIN_SENSE, 0);
8946 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8947 alc262_hp_master_update(codec);
8948}
8949
8950static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8951 unsigned int res)
8952{
8953 if ((res >> 26) != ALC880_HP_EVENT)
8954 return;
8955 alc262_hp_wildwest_automute(codec);
8956}
8957
8958static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8959 struct snd_ctl_elem_value *ucontrol)
8960{
8961 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8962 struct alc_spec *spec = codec->spec;
8963 *ucontrol->value.integer.value = spec->master_sw;
8964 return 0;
8965}
8966
8967static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8968 struct snd_ctl_elem_value *ucontrol)
8969{
8970 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8971 struct alc_spec *spec = codec->spec;
8972 int val = !!*ucontrol->value.integer.value;
8973
8974 if (val == spec->master_sw)
8975 return 0;
8976 spec->master_sw = val;
8977 alc262_hp_master_update(codec);
8978 return 1;
8979}
8980
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008981static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008982 {
8983 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8984 .name = "Master Playback Switch",
8985 .info = snd_ctl_boolean_mono_info,
8986 .get = alc262_hp_master_sw_get,
8987 .put = alc262_hp_master_sw_put,
8988 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008989 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8990 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8991 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008992 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8993 HDA_OUTPUT),
8994 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8995 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008996 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8997 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008998 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008999 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9000 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009001 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009002 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9003 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9004 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9005 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9006 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9007 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9008 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9009 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9010 { } /* end */
9011};
9012
Kailang Yangcd7509a2007-01-26 18:33:17 +01009013static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009014 {
9015 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9016 .name = "Master Playback Switch",
9017 .info = snd_ctl_boolean_mono_info,
9018 .get = alc262_hp_master_sw_get,
9019 .put = alc262_hp_master_sw_put,
9020 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009021 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9022 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9023 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9024 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009025 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9026 HDA_OUTPUT),
9027 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9028 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009029 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9030 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009031 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009032 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9033 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9034 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9035 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9036 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9037 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9038 { } /* end */
9039};
9040
9041static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9042 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9043 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009044 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009045 { } /* end */
9046};
9047
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009048/* mute/unmute internal speaker according to the hp jack and mute state */
9049static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
9050{
9051 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009052
9053 if (force || !spec->sense_updated) {
9054 unsigned int present;
9055 present = snd_hda_codec_read(codec, 0x15, 0,
9056 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01009057 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009058 spec->sense_updated = 1;
9059 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01009060 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
9061 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009062}
9063
9064static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9065 unsigned int res)
9066{
9067 if ((res >> 26) != ALC880_HP_EVENT)
9068 return;
9069 alc262_hp_t5735_automute(codec, 1);
9070}
9071
9072static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9073{
9074 alc262_hp_t5735_automute(codec, 1);
9075}
9076
9077static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009078 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9079 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009080 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9081 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9082 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9083 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9084 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9085 { } /* end */
9086};
9087
9088static struct hda_verb alc262_hp_t5735_verbs[] = {
9089 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9090 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9091
9092 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9093 { }
9094};
9095
Kailang Yang8c427222008-01-10 13:03:59 +01009096static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009097 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9098 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009099 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9100 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009101 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9102 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9103 { } /* end */
9104};
9105
9106static struct hda_verb alc262_hp_rp5700_verbs[] = {
9107 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9108 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9109 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9110 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9111 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9112 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9113 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9114 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9115 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9116 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9117 {}
9118};
9119
9120static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9121 .num_items = 1,
9122 .items = {
9123 { "Line", 0x1 },
9124 },
9125};
9126
Takashi Iwai0724ea22007-08-23 00:31:43 +02009127/* bind hp and internal speaker mute (with plug check) */
9128static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9129 struct snd_ctl_elem_value *ucontrol)
9130{
9131 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9132 long *valp = ucontrol->value.integer.value;
9133 int change;
9134
9135 /* change hp mute */
9136 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9137 HDA_AMP_MUTE,
9138 valp[0] ? 0 : HDA_AMP_MUTE);
9139 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9140 HDA_AMP_MUTE,
9141 valp[1] ? 0 : HDA_AMP_MUTE);
9142 if (change) {
9143 /* change speaker according to HP jack state */
9144 struct alc_spec *spec = codec->spec;
9145 unsigned int mute;
9146 if (spec->jack_present)
9147 mute = HDA_AMP_MUTE;
9148 else
9149 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9150 HDA_OUTPUT, 0);
9151 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9152 HDA_AMP_MUTE, mute);
9153 }
9154 return change;
9155}
Takashi Iwai5b319542007-07-26 11:49:22 +02009156
Kailang Yang272a5272007-05-14 11:00:38 +02009157static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009158 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9159 {
9160 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9161 .name = "Master Playback Switch",
9162 .info = snd_hda_mixer_amp_switch_info,
9163 .get = snd_hda_mixer_amp_switch_get,
9164 .put = alc262_sony_master_sw_put,
9165 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9166 },
Kailang Yang272a5272007-05-14 11:00:38 +02009167 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9168 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9169 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9170 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9171 { } /* end */
9172};
9173
Kailang Yang83c34212007-07-05 11:43:05 +02009174static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9175 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9176 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9177 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9178 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9179 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9180 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9181 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9182 { } /* end */
9183};
Kailang Yang272a5272007-05-14 11:00:38 +02009184
Kailang Yangdf694da2005-12-05 19:42:22 +01009185#define alc262_capture_mixer alc882_capture_mixer
9186#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9187
9188/*
9189 * generic initialization of ADC, input mixers and output mixers
9190 */
9191static struct hda_verb alc262_init_verbs[] = {
9192 /*
9193 * Unmute ADC0-2 and set the default input to mic-in
9194 */
9195 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9196 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9197 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9198 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9199 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9200 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9201
Takashi Iwaicb53c622007-08-10 17:21:45 +02009202 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009203 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009204 * Note: PASD motherboards uses the Line In 2 as the input for
9205 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009206 */
9207 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009208 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9209 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9210 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9211 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9212 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009213
9214 /*
9215 * Set up output mixers (0x0c - 0x0e)
9216 */
9217 /* set vol=0 to output mixers */
9218 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9219 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9220 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9221 /* set up input amps for analog loopback */
9222 /* Amp Indices: DAC = 0, mixer = 1 */
9223 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9224 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9225 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9226 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9227 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9228 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9229
9230 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9231 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9232 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9233 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9234 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9235 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9236
9237 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9238 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9239 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9240 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9241 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009242
Kailang Yangdf694da2005-12-05 19:42:22 +01009243 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9244 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009245
Kailang Yangdf694da2005-12-05 19:42:22 +01009246 /* FIXME: use matrix-type input source selection */
9247 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9248 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9249 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9250 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9251 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9252 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9253 /* Input mixer2 */
9254 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9255 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9256 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9257 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9258 /* Input mixer3 */
9259 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9260 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9261 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009262 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009263
9264 { }
9265};
9266
Kailang Yang4e555fe2008-08-26 13:05:55 +02009267static struct hda_verb alc262_eapd_verbs[] = {
9268 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9269 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9270 { }
9271};
9272
Kailang Yangccc656c2006-10-17 12:32:26 +02009273static struct hda_verb alc262_hippo_unsol_verbs[] = {
9274 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9275 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9276 {}
9277};
9278
9279static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9280 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9281 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9282 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9283
9284 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9285 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9286 {}
9287};
9288
Kailang Yang272a5272007-05-14 11:00:38 +02009289static struct hda_verb alc262_sony_unsol_verbs[] = {
9290 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9291 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9292 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9293
9294 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9295 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009296 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009297};
9298
Kailang Yang4e555fe2008-08-26 13:05:55 +02009299static struct hda_input_mux alc262_dmic_capture_source = {
9300 .num_items = 2,
9301 .items = {
9302 { "Int DMic", 0x9 },
9303 { "Mic", 0x0 },
9304 },
9305};
9306
9307static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9308 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9309 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9310 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9311 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9312 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9313 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9314 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9315 {
9316 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9317 /* The multiple "Capture Source" controls confuse alsamixer
9318 * So call somewhat different..
9319 */
9320 /* .name = "Capture Source", */
9321 .name = "Input Source",
9322 .count = 1,
9323 .info = alc_mux_enum_info,
9324 .get = alc_mux_enum_get,
9325 .put = alc_mux_enum_put,
9326 },
9327 { } /* end */
9328};
9329
9330static struct hda_verb alc262_toshiba_s06_verbs[] = {
9331 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9332 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9333 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9334 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9335 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9336 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9337 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9338 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9339 {}
9340};
9341
9342static void alc262_dmic_automute(struct hda_codec *codec)
9343{
9344 unsigned int present;
9345
9346 present = snd_hda_codec_read(codec, 0x18, 0,
9347 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9348 snd_hda_codec_write(codec, 0x22, 0,
9349 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9350}
9351
9352/* toggle speaker-output according to the hp-jack state */
9353static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9354{
9355 unsigned int present;
9356 unsigned char bits;
9357
9358 present = snd_hda_codec_read(codec, 0x15, 0,
9359 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9360 bits = present ? 0 : PIN_OUT;
9361 snd_hda_codec_write(codec, 0x14, 0,
9362 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9363}
9364
9365
9366
9367/* unsolicited event for HP jack sensing */
9368static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9369 unsigned int res)
9370{
9371 if ((res >> 26) == ALC880_HP_EVENT)
9372 alc262_toshiba_s06_speaker_automute(codec);
9373 if ((res >> 26) == ALC880_MIC_EVENT)
9374 alc262_dmic_automute(codec);
9375
9376}
9377
9378static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9379{
9380 alc262_toshiba_s06_speaker_automute(codec);
9381 alc262_dmic_automute(codec);
9382}
9383
Kailang Yangccc656c2006-10-17 12:32:26 +02009384/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009385static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009386{
9387 struct alc_spec *spec = codec->spec;
9388 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009389 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009390
Takashi Iwai5b319542007-07-26 11:49:22 +02009391 /* need to execute and sync at first */
9392 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9393 present = snd_hda_codec_read(codec, 0x15, 0,
9394 AC_VERB_GET_PIN_SENSE, 0);
9395 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009396 if (spec->jack_present) {
9397 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009398 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9399 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009400 } else {
9401 /* unmute internal speaker if necessary */
9402 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009403 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9404 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009405 }
9406}
9407
9408/* unsolicited event for HP jack sensing */
9409static void alc262_hippo_unsol_event(struct hda_codec *codec,
9410 unsigned int res)
9411{
9412 if ((res >> 26) != ALC880_HP_EVENT)
9413 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009414 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009415}
9416
Takashi Iwai5b319542007-07-26 11:49:22 +02009417static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009418{
Kailang Yangccc656c2006-10-17 12:32:26 +02009419 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009420 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009421
Takashi Iwai5b319542007-07-26 11:49:22 +02009422 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9423 present = snd_hda_codec_read(codec, 0x1b, 0,
9424 AC_VERB_GET_PIN_SENSE, 0);
9425 present = (present & 0x80000000) != 0;
9426 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009427 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009428 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9429 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009430 } else {
9431 /* unmute internal speaker if necessary */
9432 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009433 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9434 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009435 }
9436}
9437
9438/* unsolicited event for HP jack sensing */
9439static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9440 unsigned int res)
9441{
9442 if ((res >> 26) != ALC880_HP_EVENT)
9443 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009444 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009445}
9446
Takashi Iwai834be882006-03-01 14:16:17 +01009447/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009448 * nec model
9449 * 0x15 = headphone
9450 * 0x16 = internal speaker
9451 * 0x18 = external mic
9452 */
9453
9454static struct snd_kcontrol_new alc262_nec_mixer[] = {
9455 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9456 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9457
9458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9459 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9460 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9461
9462 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9463 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9464 { } /* end */
9465};
9466
9467static struct hda_verb alc262_nec_verbs[] = {
9468 /* Unmute Speaker */
9469 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9470
9471 /* Headphone */
9472 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9473 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9474
9475 /* External mic to headphone */
9476 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9477 /* External mic to speaker */
9478 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9479 {}
9480};
9481
9482/*
Takashi Iwai834be882006-03-01 14:16:17 +01009483 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009484 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9485 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009486 */
9487
9488#define ALC_HP_EVENT 0x37
9489
9490static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9491 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9492 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009493 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9494 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009495 {}
9496};
9497
Jiang zhe0e31daf2008-03-20 12:12:39 +01009498static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9499 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9500 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9501 {}
9502};
9503
Takashi Iwai834be882006-03-01 14:16:17 +01009504static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009505 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009506 .items = {
9507 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009508 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009509 { "CD", 0x4 },
9510 },
9511};
9512
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009513static struct hda_input_mux alc262_HP_capture_source = {
9514 .num_items = 5,
9515 .items = {
9516 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009517 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009518 { "Line", 0x2 },
9519 { "CD", 0x4 },
9520 { "AUX IN", 0x6 },
9521 },
9522};
9523
zhejiangaccbe492007-08-31 12:36:05 +02009524static struct hda_input_mux alc262_HP_D7000_capture_source = {
9525 .num_items = 4,
9526 .items = {
9527 { "Mic", 0x0 },
9528 { "Front Mic", 0x2 },
9529 { "Line", 0x1 },
9530 { "CD", 0x4 },
9531 },
9532};
9533
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009534/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009535static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9536{
9537 struct alc_spec *spec = codec->spec;
9538 unsigned int mute;
9539
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009540 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009541 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009542 /* need to execute and sync at first */
9543 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009544 /* check laptop HP jack */
9545 present = snd_hda_codec_read(codec, 0x14, 0,
9546 AC_VERB_GET_PIN_SENSE, 0);
9547 /* need to execute and sync at first */
9548 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9549 /* check docking HP jack */
9550 present |= snd_hda_codec_read(codec, 0x1b, 0,
9551 AC_VERB_GET_PIN_SENSE, 0);
9552 if (present & AC_PINSENSE_PRESENCE)
9553 spec->jack_present = 1;
9554 else
9555 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009556 spec->sense_updated = 1;
9557 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009558 /* unmute internal speaker only if both HPs are unplugged and
9559 * master switch is on
9560 */
9561 if (spec->jack_present)
9562 mute = HDA_AMP_MUTE;
9563 else
Takashi Iwai834be882006-03-01 14:16:17 +01009564 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009565 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9566 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009567}
9568
9569/* unsolicited event for HP jack sensing */
9570static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9571 unsigned int res)
9572{
9573 if ((res >> 26) != ALC_HP_EVENT)
9574 return;
9575 alc262_fujitsu_automute(codec, 1);
9576}
9577
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009578static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9579{
9580 alc262_fujitsu_automute(codec, 1);
9581}
9582
Takashi Iwai834be882006-03-01 14:16:17 +01009583/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009584static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9585 .ops = &snd_hda_bind_vol,
9586 .values = {
9587 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9588 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
9589 0
9590 },
9591};
Takashi Iwai834be882006-03-01 14:16:17 +01009592
Jiang zhe0e31daf2008-03-20 12:12:39 +01009593/* mute/unmute internal speaker according to the hp jack and mute state */
9594static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
9595{
9596 struct alc_spec *spec = codec->spec;
9597 unsigned int mute;
9598
9599 if (force || !spec->sense_updated) {
9600 unsigned int present_int_hp;
9601 /* need to execute and sync at first */
9602 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9603 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
9604 AC_VERB_GET_PIN_SENSE, 0);
9605 spec->jack_present = (present_int_hp & 0x80000000) != 0;
9606 spec->sense_updated = 1;
9607 }
9608 if (spec->jack_present) {
9609 /* mute internal speaker */
9610 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9611 HDA_AMP_MUTE, HDA_AMP_MUTE);
9612 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9613 HDA_AMP_MUTE, HDA_AMP_MUTE);
9614 } else {
9615 /* unmute internal speaker if necessary */
9616 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9617 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9618 HDA_AMP_MUTE, mute);
9619 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9620 HDA_AMP_MUTE, mute);
9621 }
9622}
9623
9624/* unsolicited event for HP jack sensing */
9625static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
9626 unsigned int res)
9627{
9628 if ((res >> 26) != ALC_HP_EVENT)
9629 return;
9630 alc262_lenovo_3000_automute(codec, 1);
9631}
9632
Takashi Iwai834be882006-03-01 14:16:17 +01009633/* bind hp and internal speaker mute (with plug check) */
9634static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
9635 struct snd_ctl_elem_value *ucontrol)
9636{
9637 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9638 long *valp = ucontrol->value.integer.value;
9639 int change;
9640
Tony Vroon5d9fab22008-03-14 17:09:18 +01009641 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9642 HDA_AMP_MUTE,
9643 valp ? 0 : HDA_AMP_MUTE);
9644 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9645 HDA_AMP_MUTE,
9646 valp ? 0 : HDA_AMP_MUTE);
9647
Takashi Iwai82beb8f2007-08-10 17:09:26 +02009648 if (change)
9649 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01009650 return change;
9651}
9652
9653static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02009654 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01009655 {
9656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9657 .name = "Master Playback Switch",
9658 .info = snd_hda_mixer_amp_switch_info,
9659 .get = snd_hda_mixer_amp_switch_get,
9660 .put = alc262_fujitsu_master_sw_put,
9661 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9662 },
9663 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9664 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02009665 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
9666 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009667 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9668 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9669 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009670 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9671 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9672 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009673 { } /* end */
9674};
9675
Jiang zhe0e31daf2008-03-20 12:12:39 +01009676/* bind hp and internal speaker mute (with plug check) */
9677static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
9678 struct snd_ctl_elem_value *ucontrol)
9679{
9680 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9681 long *valp = ucontrol->value.integer.value;
9682 int change;
9683
9684 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9685 HDA_AMP_MUTE,
9686 valp ? 0 : HDA_AMP_MUTE);
9687
9688 if (change)
9689 alc262_lenovo_3000_automute(codec, 0);
9690 return change;
9691}
9692
9693static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
9694 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9695 {
9696 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9697 .name = "Master Playback Switch",
9698 .info = snd_hda_mixer_amp_switch_info,
9699 .get = snd_hda_mixer_amp_switch_get,
9700 .put = alc262_lenovo_3000_master_sw_put,
9701 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
9702 },
9703 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9704 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9705 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9707 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9708 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9709 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9710 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9711 { } /* end */
9712};
9713
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009714/* additional init verbs for Benq laptops */
9715static struct hda_verb alc262_EAPD_verbs[] = {
9716 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9717 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9718 {}
9719};
9720
Kailang Yang83c34212007-07-05 11:43:05 +02009721static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
9722 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9723 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9724
9725 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9726 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
9727 {}
9728};
9729
Tobin Davisf651b502007-10-26 12:40:47 +02009730/* Samsung Q1 Ultra Vista model setup */
9731static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009732 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9733 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009734 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9735 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9736 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009737 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009738 { } /* end */
9739};
9740
9741static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009742 /* output mixer */
9743 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9744 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9745 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9746 /* speaker */
9747 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9748 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9749 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9750 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9751 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02009752 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009753 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9754 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9755 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9756 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9757 /* internal mic */
9758 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9759 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9760 /* ADC, choose mic */
9761 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9762 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9763 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9764 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9765 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9766 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9767 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9768 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9769 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9770 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009771 {}
9772};
9773
Tobin Davisf651b502007-10-26 12:40:47 +02009774/* mute/unmute internal speaker according to the hp jack and mute state */
9775static void alc262_ultra_automute(struct hda_codec *codec)
9776{
9777 struct alc_spec *spec = codec->spec;
9778 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009779
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009780 mute = 0;
9781 /* auto-mute only when HP is used as HP */
9782 if (!spec->cur_mux[0]) {
9783 unsigned int present;
9784 /* need to execute and sync at first */
9785 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9786 present = snd_hda_codec_read(codec, 0x15, 0,
9787 AC_VERB_GET_PIN_SENSE, 0);
9788 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9789 if (spec->jack_present)
9790 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009791 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009792 /* mute/unmute internal speaker */
9793 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9794 HDA_AMP_MUTE, mute);
9795 /* mute/unmute HP */
9796 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9797 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009798}
9799
9800/* unsolicited event for HP jack sensing */
9801static void alc262_ultra_unsol_event(struct hda_codec *codec,
9802 unsigned int res)
9803{
9804 if ((res >> 26) != ALC880_HP_EVENT)
9805 return;
9806 alc262_ultra_automute(codec);
9807}
9808
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009809static struct hda_input_mux alc262_ultra_capture_source = {
9810 .num_items = 2,
9811 .items = {
9812 { "Mic", 0x1 },
9813 { "Headphone", 0x7 },
9814 },
9815};
9816
9817static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9818 struct snd_ctl_elem_value *ucontrol)
9819{
9820 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9821 struct alc_spec *spec = codec->spec;
9822 int ret;
9823
9824 ret = alc882_mux_enum_put(kcontrol, ucontrol);
9825 if (!ret)
9826 return 0;
9827 /* reprogram the HP pin as mic or HP according to the input source */
9828 snd_hda_codec_write_cache(codec, 0x15, 0,
9829 AC_VERB_SET_PIN_WIDGET_CONTROL,
9830 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9831 alc262_ultra_automute(codec); /* mute/unmute HP */
9832 return ret;
9833}
9834
9835static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9836 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9837 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9838 {
9839 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9840 .name = "Capture Source",
9841 .info = alc882_mux_enum_info,
9842 .get = alc882_mux_enum_get,
9843 .put = alc262_ultra_mux_enum_put,
9844 },
9845 { } /* end */
9846};
9847
Kailang Yangdf694da2005-12-05 19:42:22 +01009848/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009849static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9850 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009851{
9852 hda_nid_t nid;
9853 int err;
9854
9855 spec->multiout.num_dacs = 1; /* only use one dac */
9856 spec->multiout.dac_nids = spec->private_dac_nids;
9857 spec->multiout.dac_nids[0] = 2;
9858
9859 nid = cfg->line_out_pins[0];
9860 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009861 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9862 "Front Playback Volume",
9863 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
9864 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009865 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009866 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9867 "Front Playback Switch",
9868 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9869 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009870 return err;
9871 }
9872
Takashi Iwai82bc9552006-03-21 11:24:42 +01009873 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009874 if (nid) {
9875 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009876 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9877 "Speaker Playback Volume",
9878 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9879 HDA_OUTPUT));
9880 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009881 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009882 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9883 "Speaker Playback Switch",
9884 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9885 HDA_OUTPUT));
9886 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009887 return err;
9888 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009889 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9890 "Speaker Playback Switch",
9891 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9892 HDA_OUTPUT));
9893 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009894 return err;
9895 }
9896 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009897 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009898 if (nid) {
9899 /* spec->multiout.hp_nid = 2; */
9900 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009901 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9902 "Headphone Playback Volume",
9903 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9904 HDA_OUTPUT));
9905 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009906 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009907 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9908 "Headphone Playback Switch",
9909 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9910 HDA_OUTPUT));
9911 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009912 return err;
9913 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009914 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9915 "Headphone Playback Switch",
9916 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9917 HDA_OUTPUT));
9918 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009919 return err;
9920 }
9921 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009922 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009923}
9924
9925/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009926#define alc262_auto_create_analog_input_ctls \
9927 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009928
9929/*
9930 * generic initialization of ADC, input mixers and output mixers
9931 */
9932static struct hda_verb alc262_volume_init_verbs[] = {
9933 /*
9934 * Unmute ADC0-2 and set the default input to mic-in
9935 */
9936 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9937 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9938 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9939 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9940 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9941 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9942
Takashi Iwaicb53c622007-08-10 17:21:45 +02009943 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009944 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009945 * Note: PASD motherboards uses the Line In 2 as the input for
9946 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009947 */
9948 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009949 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9950 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9951 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9952 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9953 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009954
9955 /*
9956 * Set up output mixers (0x0c - 0x0f)
9957 */
9958 /* set vol=0 to output mixers */
9959 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9960 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9961 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +02009962
Kailang Yangdf694da2005-12-05 19:42:22 +01009963 /* set up input amps for analog loopback */
9964 /* Amp Indices: DAC = 0, mixer = 1 */
9965 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9966 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9967 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9968 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9969 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9970 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9971
9972 /* FIXME: use matrix-type input source selection */
9973 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9974 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9975 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9976 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9977 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9978 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9979 /* Input mixer2 */
9980 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9981 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9982 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9983 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9984 /* Input mixer3 */
9985 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9986 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9987 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9988 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9989
9990 { }
9991};
9992
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009993static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9994 /*
9995 * Unmute ADC0-2 and set the default input to mic-in
9996 */
9997 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9998 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9999 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10000 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10001 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10002 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10003
Takashi Iwaicb53c622007-08-10 17:21:45 +020010004 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010005 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010006 * Note: PASD motherboards uses the Line In 2 as the input for
10007 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010008 */
10009 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10014 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10015 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10016 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010017
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010018 /*
10019 * Set up output mixers (0x0c - 0x0e)
10020 */
10021 /* set vol=0 to output mixers */
10022 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10023 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10024 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10025
10026 /* set up input amps for analog loopback */
10027 /* Amp Indices: DAC = 0, mixer = 1 */
10028 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10029 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10030 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10031 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10032 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10033 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10034
Takashi Iwaice875f02008-01-28 18:17:43 +010010035 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010036 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10037 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10038
10039 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10040 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10041
10042 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10043 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10044
10045 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10046 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10047 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10048 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10049 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10050
10051 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10052 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10053 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10054 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10055 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10056 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10057
10058
10059 /* FIXME: use matrix-type input source selection */
10060 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10061 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10062 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10063 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10064 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10065 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10066 /* Input mixer2 */
10067 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10068 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10069 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10070 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10071 /* Input mixer3 */
10072 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10073 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10074 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10075 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10076
Takashi Iwaice875f02008-01-28 18:17:43 +010010077 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10078
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010079 { }
10080};
10081
Kailang Yangcd7509a2007-01-26 18:33:17 +010010082static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10083 /*
10084 * Unmute ADC0-2 and set the default input to mic-in
10085 */
10086 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10087 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10088 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10089 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10090 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10091 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10092
Takashi Iwaicb53c622007-08-10 17:21:45 +020010093 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010094 * mixer widget
10095 * Note: PASD motherboards uses the Line In 2 as the input for front
10096 * panel mic (mic 2)
10097 */
10098 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10100 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10101 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10102 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10103 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10104 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10105 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10106 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010107 /*
10108 * Set up output mixers (0x0c - 0x0e)
10109 */
10110 /* set vol=0 to output mixers */
10111 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10112 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10113 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10114
10115 /* set up input amps for analog loopback */
10116 /* Amp Indices: DAC = 0, mixer = 1 */
10117 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10118 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10119 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10120 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10121 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10122 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10123
10124
10125 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10126 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10127 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10128 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10129 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10130 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10131 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10132
10133 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10134 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10135
10136 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10137 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10138
10139 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10140 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10141 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10142 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10143 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10144 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10145
10146 /* FIXME: use matrix-type input source selection */
10147 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10148 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10149 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10150 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10151 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10152 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10153 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10154 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10155 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10156 /* Input mixer2 */
10157 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10158 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10159 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10160 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10161 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10162 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10163 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10164 /* Input mixer3 */
10165 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10166 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10167 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10168 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10169 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10170 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10171 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10172
Takashi Iwaice875f02008-01-28 18:17:43 +010010173 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10174
Kailang Yangcd7509a2007-01-26 18:33:17 +010010175 { }
10176};
10177
Takashi Iwaicb53c622007-08-10 17:21:45 +020010178#ifdef CONFIG_SND_HDA_POWER_SAVE
10179#define alc262_loopbacks alc880_loopbacks
10180#endif
10181
Kailang Yangdf694da2005-12-05 19:42:22 +010010182/* pcm configuration: identiacal with ALC880 */
10183#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10184#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10185#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10186#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10187
10188/*
10189 * BIOS auto configuration
10190 */
10191static int alc262_parse_auto_config(struct hda_codec *codec)
10192{
10193 struct alc_spec *spec = codec->spec;
10194 int err;
10195 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10196
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010197 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10198 alc262_ignore);
10199 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010200 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010201 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010202 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010203 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10204 if (err < 0)
10205 return err;
10206 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10207 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010208 return err;
10209
10210 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10211
10212 if (spec->autocfg.dig_out_pin)
10213 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
10214 if (spec->autocfg.dig_in_pin)
10215 spec->dig_in_nid = ALC262_DIGIN_NID;
10216
10217 if (spec->kctl_alloc)
10218 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10219
10220 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010221 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010222 spec->input_mux = &spec->private_imux;
10223
Takashi Iwai776e1842007-08-29 15:07:11 +020010224 err = alc_auto_add_mic_boost(codec);
10225 if (err < 0)
10226 return err;
10227
Kailang Yangdf694da2005-12-05 19:42:22 +010010228 return 1;
10229}
10230
10231#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10232#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10233#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010234#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010235
10236
10237/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010238static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010239{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010240 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010241 alc262_auto_init_multi_out(codec);
10242 alc262_auto_init_hp_out(codec);
10243 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010244 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010245 if (spec->unsol_event)
10246 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010247}
10248
10249/*
10250 * configuration and preset
10251 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010252static const char *alc262_models[ALC262_MODEL_LAST] = {
10253 [ALC262_BASIC] = "basic",
10254 [ALC262_HIPPO] = "hippo",
10255 [ALC262_HIPPO_1] = "hippo_1",
10256 [ALC262_FUJITSU] = "fujitsu",
10257 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010258 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010259 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010260 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010261 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010262 [ALC262_BENQ_T31] = "benq-t31",
10263 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +020010264 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010265 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010266 [ALC262_NEC] = "nec",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010267 [ALC262_AUTO] = "auto",
10268};
10269
10270static struct snd_pci_quirk alc262_cfg_tbl[] = {
10271 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010272 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010273 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010274 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010275 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10276 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010277 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010278 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010279 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010280 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010281 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010282 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010283 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010284 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010285 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010286 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010287 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010288 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010289 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10290 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10291 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010292 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10293 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010294 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010295 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010296 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010297 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10298 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10299 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010300 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
10301 ALC262_SONY_ASSAMD),
Kailang Yang4e555fe2008-08-26 13:05:55 +020010302 SND_PCI_QUIRK(0x1179, 0x0268, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010303 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010304 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010305 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010306 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010307 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010308 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010309 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010310 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010311 {}
10312};
10313
10314static struct alc_config_preset alc262_presets[] = {
10315 [ALC262_BASIC] = {
10316 .mixers = { alc262_base_mixer },
10317 .init_verbs = { alc262_init_verbs },
10318 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10319 .dac_nids = alc262_dac_nids,
10320 .hp_nid = 0x03,
10321 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10322 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010323 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010324 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010325 [ALC262_HIPPO] = {
10326 .mixers = { alc262_base_mixer },
10327 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10328 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10329 .dac_nids = alc262_dac_nids,
10330 .hp_nid = 0x03,
10331 .dig_out_nid = ALC262_DIGOUT_NID,
10332 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10333 .channel_mode = alc262_modes,
10334 .input_mux = &alc262_capture_source,
10335 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010336 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010337 },
10338 [ALC262_HIPPO_1] = {
10339 .mixers = { alc262_hippo1_mixer },
10340 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10341 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10342 .dac_nids = alc262_dac_nids,
10343 .hp_nid = 0x02,
10344 .dig_out_nid = ALC262_DIGOUT_NID,
10345 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10346 .channel_mode = alc262_modes,
10347 .input_mux = &alc262_capture_source,
10348 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010349 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010350 },
Takashi Iwai834be882006-03-01 14:16:17 +010010351 [ALC262_FUJITSU] = {
10352 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010353 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10354 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010355 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10356 .dac_nids = alc262_dac_nids,
10357 .hp_nid = 0x03,
10358 .dig_out_nid = ALC262_DIGOUT_NID,
10359 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10360 .channel_mode = alc262_modes,
10361 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010362 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010363 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010364 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010365 [ALC262_HP_BPC] = {
10366 .mixers = { alc262_HP_BPC_mixer },
10367 .init_verbs = { alc262_HP_BPC_init_verbs },
10368 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10369 .dac_nids = alc262_dac_nids,
10370 .hp_nid = 0x03,
10371 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10372 .channel_mode = alc262_modes,
10373 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010374 .unsol_event = alc262_hp_bpc_unsol_event,
10375 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010376 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010377 [ALC262_HP_BPC_D7000_WF] = {
10378 .mixers = { alc262_HP_BPC_WildWest_mixer },
10379 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10380 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10381 .dac_nids = alc262_dac_nids,
10382 .hp_nid = 0x03,
10383 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10384 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010385 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010386 .unsol_event = alc262_hp_wildwest_unsol_event,
10387 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010388 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010389 [ALC262_HP_BPC_D7000_WL] = {
10390 .mixers = { alc262_HP_BPC_WildWest_mixer,
10391 alc262_HP_BPC_WildWest_option_mixer },
10392 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10393 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10394 .dac_nids = alc262_dac_nids,
10395 .hp_nid = 0x03,
10396 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10397 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010398 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010399 .unsol_event = alc262_hp_wildwest_unsol_event,
10400 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010401 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010402 [ALC262_HP_TC_T5735] = {
10403 .mixers = { alc262_hp_t5735_mixer },
10404 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10405 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10406 .dac_nids = alc262_dac_nids,
10407 .hp_nid = 0x03,
10408 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10409 .channel_mode = alc262_modes,
10410 .input_mux = &alc262_capture_source,
10411 .unsol_event = alc262_hp_t5735_unsol_event,
10412 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010413 },
10414 [ALC262_HP_RP5700] = {
10415 .mixers = { alc262_hp_rp5700_mixer },
10416 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10417 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10418 .dac_nids = alc262_dac_nids,
10419 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10420 .channel_mode = alc262_modes,
10421 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010422 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010423 [ALC262_BENQ_ED8] = {
10424 .mixers = { alc262_base_mixer },
10425 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10426 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10427 .dac_nids = alc262_dac_nids,
10428 .hp_nid = 0x03,
10429 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10430 .channel_mode = alc262_modes,
10431 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010432 },
Kailang Yang272a5272007-05-14 11:00:38 +020010433 [ALC262_SONY_ASSAMD] = {
10434 .mixers = { alc262_sony_mixer },
10435 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10436 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10437 .dac_nids = alc262_dac_nids,
10438 .hp_nid = 0x02,
10439 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10440 .channel_mode = alc262_modes,
10441 .input_mux = &alc262_capture_source,
10442 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010443 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010444 },
10445 [ALC262_BENQ_T31] = {
10446 .mixers = { alc262_benq_t31_mixer },
10447 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10448 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10449 .dac_nids = alc262_dac_nids,
10450 .hp_nid = 0x03,
10451 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10452 .channel_mode = alc262_modes,
10453 .input_mux = &alc262_capture_source,
10454 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010455 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010456 },
Tobin Davisf651b502007-10-26 12:40:47 +020010457 [ALC262_ULTRA] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010458 .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
10459 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010460 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10461 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010462 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10463 .channel_mode = alc262_modes,
10464 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010465 .adc_nids = alc262_adc_nids, /* ADC0 */
10466 .capsrc_nids = alc262_capsrc_nids,
10467 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010468 .unsol_event = alc262_ultra_unsol_event,
10469 .init_hook = alc262_ultra_automute,
10470 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010471 [ALC262_LENOVO_3000] = {
10472 .mixers = { alc262_lenovo_3000_mixer },
10473 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10474 alc262_lenovo_3000_unsol_verbs },
10475 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10476 .dac_nids = alc262_dac_nids,
10477 .hp_nid = 0x03,
10478 .dig_out_nid = ALC262_DIGOUT_NID,
10479 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10480 .channel_mode = alc262_modes,
10481 .input_mux = &alc262_fujitsu_capture_source,
10482 .unsol_event = alc262_lenovo_3000_unsol_event,
10483 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010484 [ALC262_NEC] = {
10485 .mixers = { alc262_nec_mixer },
10486 .init_verbs = { alc262_nec_verbs },
10487 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10488 .dac_nids = alc262_dac_nids,
10489 .hp_nid = 0x03,
10490 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10491 .channel_mode = alc262_modes,
10492 .input_mux = &alc262_capture_source,
10493 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010494 [ALC262_TOSHIBA_S06] = {
10495 .mixers = { alc262_toshiba_s06_mixer },
10496 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10497 alc262_eapd_verbs },
10498 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10499 .capsrc_nids = alc262_dmic_capsrc_nids,
10500 .dac_nids = alc262_dac_nids,
10501 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10502 .dig_out_nid = ALC262_DIGOUT_NID,
10503 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10504 .channel_mode = alc262_modes,
10505 .input_mux = &alc262_dmic_capture_source,
10506 .unsol_event = alc262_toshiba_s06_unsol_event,
10507 .init_hook = alc262_toshiba_s06_init_hook,
10508 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010509};
10510
10511static int patch_alc262(struct hda_codec *codec)
10512{
10513 struct alc_spec *spec;
10514 int board_config;
10515 int err;
10516
Robert P. J. Daydc041e02006-12-19 14:44:15 +010010517 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010010518 if (spec == NULL)
10519 return -ENOMEM;
10520
10521 codec->spec = spec;
10522#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010523 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
10524 * under-run
10525 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010526 {
10527 int tmp;
10528 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10529 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
10530 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10531 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
10532 }
10533#endif
10534
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020010535 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10536
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010537 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
10538 alc262_models,
10539 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010010540
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010541 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010542 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
10543 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010544 board_config = ALC262_AUTO;
10545 }
10546
10547 if (board_config == ALC262_AUTO) {
10548 /* automatic parse from the BIOS config */
10549 err = alc262_parse_auto_config(codec);
10550 if (err < 0) {
10551 alc_free(codec);
10552 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010553 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010554 printk(KERN_INFO
10555 "hda_codec: Cannot set up configuration "
10556 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010557 board_config = ALC262_BASIC;
10558 }
10559 }
10560
10561 if (board_config != ALC262_AUTO)
10562 setup_preset(spec, &alc262_presets[board_config]);
10563
10564 spec->stream_name_analog = "ALC262 Analog";
10565 spec->stream_analog_playback = &alc262_pcm_analog_playback;
10566 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020010567
Kailang Yangdf694da2005-12-05 19:42:22 +010010568 spec->stream_name_digital = "ALC262 Digital";
10569 spec->stream_digital_playback = &alc262_pcm_digital_playback;
10570 spec->stream_digital_capture = &alc262_pcm_digital_capture;
10571
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010572 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010573 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010010574 unsigned int wcap = get_wcaps(codec, 0x07);
10575
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010576 /* get type */
10577 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010010578 if (wcap != AC_WID_AUD_IN) {
10579 spec->adc_nids = alc262_adc_nids_alt;
10580 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010581 spec->capsrc_nids = alc262_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010582 spec->mixers[spec->num_mixers] =
10583 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +010010584 spec->num_mixers++;
10585 } else {
10586 spec->adc_nids = alc262_adc_nids;
10587 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010588 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010010589 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
10590 spec->num_mixers++;
10591 }
10592 }
10593
Takashi Iwai2134ea42008-01-10 16:53:55 +010010594 spec->vmaster_nid = 0x0c;
10595
Kailang Yangdf694da2005-12-05 19:42:22 +010010596 codec->patch_ops = alc_patch_ops;
10597 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010598 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010599#ifdef CONFIG_SND_HDA_POWER_SAVE
10600 if (!spec->loopback.amplist)
10601 spec->loopback.amplist = alc262_loopbacks;
10602#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020010603
Kailang Yangdf694da2005-12-05 19:42:22 +010010604 return 0;
10605}
10606
Kailang Yangdf694da2005-12-05 19:42:22 +010010607/*
Kailang Yanga361d842007-06-05 12:30:55 +020010608 * ALC268 channel source setting (2 channel)
10609 */
10610#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
10611#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020010612
Kailang Yanga361d842007-06-05 12:30:55 +020010613static hda_nid_t alc268_dac_nids[2] = {
10614 /* front, hp */
10615 0x02, 0x03
10616};
10617
10618static hda_nid_t alc268_adc_nids[2] = {
10619 /* ADC0-1 */
10620 0x08, 0x07
10621};
10622
10623static hda_nid_t alc268_adc_nids_alt[1] = {
10624 /* ADC0 */
10625 0x08
10626};
10627
Takashi Iwaie1406342008-02-11 18:32:32 +010010628static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
10629
Kailang Yanga361d842007-06-05 12:30:55 +020010630static struct snd_kcontrol_new alc268_base_mixer[] = {
10631 /* output mixer control */
10632 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10633 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10634 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10635 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010636 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10637 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10638 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020010639 { }
10640};
10641
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010642/* bind Beep switches of both NID 0x0f and 0x10 */
10643static struct hda_bind_ctls alc268_bind_beep_sw = {
10644 .ops = &snd_hda_bind_sw,
10645 .values = {
10646 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
10647 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
10648 0
10649 },
10650};
10651
10652static struct snd_kcontrol_new alc268_beep_mixer[] = {
10653 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
10654 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
10655 { }
10656};
10657
Kailang Yangd1a991a2007-08-15 16:21:59 +020010658static struct hda_verb alc268_eapd_verbs[] = {
10659 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10660 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10661 { }
10662};
10663
Takashi Iwaid2738092007-08-16 14:59:45 +020010664/* Toshiba specific */
10665#define alc268_toshiba_automute alc262_hippo_automute
10666
10667static struct hda_verb alc268_toshiba_verbs[] = {
10668 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10669 { } /* end */
10670};
10671
Kailang Yang8ef355d2008-08-26 13:10:22 +020010672static struct hda_input_mux alc268_acer_lc_capture_source = {
10673 .num_items = 2,
10674 .items = {
10675 { "i-Mic", 0x6 },
10676 { "E-Mic", 0x0 },
10677 },
10678};
10679
Takashi Iwaid2738092007-08-16 14:59:45 +020010680/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020010681/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020010682static struct hda_bind_ctls alc268_acer_bind_master_vol = {
10683 .ops = &snd_hda_bind_vol,
10684 .values = {
10685 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
10686 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
10687 0
10688 },
10689};
10690
Takashi Iwai889c4392007-08-23 18:56:52 +020010691/* mute/unmute internal speaker according to the hp jack and mute state */
10692static void alc268_acer_automute(struct hda_codec *codec, int force)
10693{
10694 struct alc_spec *spec = codec->spec;
10695 unsigned int mute;
10696
10697 if (force || !spec->sense_updated) {
10698 unsigned int present;
10699 present = snd_hda_codec_read(codec, 0x14, 0,
10700 AC_VERB_GET_PIN_SENSE, 0);
10701 spec->jack_present = (present & 0x80000000) != 0;
10702 spec->sense_updated = 1;
10703 }
10704 if (spec->jack_present)
10705 mute = HDA_AMP_MUTE; /* mute internal speaker */
10706 else /* unmute internal speaker if necessary */
10707 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
10708 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10709 HDA_AMP_MUTE, mute);
10710}
10711
10712
10713/* bind hp and internal speaker mute (with plug check) */
10714static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
10715 struct snd_ctl_elem_value *ucontrol)
10716{
10717 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10718 long *valp = ucontrol->value.integer.value;
10719 int change;
10720
10721 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
10722 HDA_AMP_MUTE,
10723 valp[0] ? 0 : HDA_AMP_MUTE);
10724 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
10725 HDA_AMP_MUTE,
10726 valp[1] ? 0 : HDA_AMP_MUTE);
10727 if (change)
10728 alc268_acer_automute(codec, 0);
10729 return change;
10730}
Takashi Iwaid2738092007-08-16 14:59:45 +020010731
Kailang Yang8ef355d2008-08-26 13:10:22 +020010732static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
10733 /* output mixer control */
10734 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10735 {
10736 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10737 .name = "Master Playback Switch",
10738 .info = snd_hda_mixer_amp_switch_info,
10739 .get = snd_hda_mixer_amp_switch_get,
10740 .put = alc268_acer_master_sw_put,
10741 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10742 },
10743 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
10744 { }
10745};
10746
Takashi Iwaid2738092007-08-16 14:59:45 +020010747static struct snd_kcontrol_new alc268_acer_mixer[] = {
10748 /* output mixer control */
10749 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10750 {
10751 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10752 .name = "Master Playback Switch",
10753 .info = snd_hda_mixer_amp_switch_info,
10754 .get = snd_hda_mixer_amp_switch_get,
10755 .put = alc268_acer_master_sw_put,
10756 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10757 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010758 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10759 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10760 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020010761 { }
10762};
10763
Kailang Yang8ef355d2008-08-26 13:10:22 +020010764static struct hda_verb alc268_acer_aspire_one_verbs[] = {
10765 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10766 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10767 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10768 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10769 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
10770 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
10771 { }
10772};
10773
Takashi Iwaid2738092007-08-16 14:59:45 +020010774static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010775 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
10776 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020010777 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10778 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010779 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10780 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020010781 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10782 { }
10783};
10784
10785/* unsolicited event for HP jack sensing */
10786static void alc268_toshiba_unsol_event(struct hda_codec *codec,
10787 unsigned int res)
10788{
Takashi Iwai889c4392007-08-23 18:56:52 +020010789 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010790 return;
10791 alc268_toshiba_automute(codec);
10792}
10793
10794static void alc268_acer_unsol_event(struct hda_codec *codec,
10795 unsigned int res)
10796{
Takashi Iwai889c4392007-08-23 18:56:52 +020010797 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010798 return;
10799 alc268_acer_automute(codec, 1);
10800}
10801
Takashi Iwai889c4392007-08-23 18:56:52 +020010802static void alc268_acer_init_hook(struct hda_codec *codec)
10803{
10804 alc268_acer_automute(codec, 1);
10805}
10806
Kailang Yang8ef355d2008-08-26 13:10:22 +020010807/* toggle speaker-output according to the hp-jack state */
10808static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
10809{
10810 unsigned int present;
10811 unsigned char bits;
10812
10813 present = snd_hda_codec_read(codec, 0x15, 0,
10814 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10815 bits = present ? AMP_IN_MUTE(0) : 0;
10816 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
10817 AMP_IN_MUTE(0), bits);
10818 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
10819 AMP_IN_MUTE(0), bits);
10820}
10821
10822
10823static void alc268_acer_mic_automute(struct hda_codec *codec)
10824{
10825 unsigned int present;
10826
10827 present = snd_hda_codec_read(codec, 0x18, 0,
10828 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10829 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
10830 present ? 0x0 : 0x6);
10831}
10832
10833static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
10834 unsigned int res)
10835{
10836 if ((res >> 26) == ALC880_HP_EVENT)
10837 alc268_aspire_one_speaker_automute(codec);
10838 if ((res >> 26) == ALC880_MIC_EVENT)
10839 alc268_acer_mic_automute(codec);
10840}
10841
10842static void alc268_acer_lc_init_hook(struct hda_codec *codec)
10843{
10844 alc268_aspire_one_speaker_automute(codec);
10845 alc268_acer_mic_automute(codec);
10846}
10847
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010848static struct snd_kcontrol_new alc268_dell_mixer[] = {
10849 /* output mixer control */
10850 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10851 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10852 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10853 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10854 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10855 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10856 { }
10857};
10858
10859static struct hda_verb alc268_dell_verbs[] = {
10860 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10861 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10862 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10863 { }
10864};
10865
10866/* mute/unmute internal speaker according to the hp jack and mute state */
10867static void alc268_dell_automute(struct hda_codec *codec)
10868{
10869 unsigned int present;
10870 unsigned int mute;
10871
10872 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
10873 if (present & 0x80000000)
10874 mute = HDA_AMP_MUTE;
10875 else
10876 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
10877 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10878 HDA_AMP_MUTE, mute);
10879}
10880
10881static void alc268_dell_unsol_event(struct hda_codec *codec,
10882 unsigned int res)
10883{
10884 if ((res >> 26) != ALC880_HP_EVENT)
10885 return;
10886 alc268_dell_automute(codec);
10887}
10888
10889#define alc268_dell_init_hook alc268_dell_automute
10890
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010891static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
10892 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10893 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10894 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10895 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10896 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10897 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
10898 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
10899 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10900 { }
10901};
10902
10903static struct hda_verb alc267_quanta_il1_verbs[] = {
10904 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10905 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
10906 { }
10907};
10908
10909static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
10910{
10911 unsigned int present;
10912
10913 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
10914 & AC_PINSENSE_PRESENCE;
10915 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10916 present ? 0 : PIN_OUT);
10917}
10918
10919static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
10920{
10921 unsigned int present;
10922
10923 present = snd_hda_codec_read(codec, 0x18, 0,
10924 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10925 snd_hda_codec_write(codec, 0x23, 0,
10926 AC_VERB_SET_CONNECT_SEL,
10927 present ? 0x00 : 0x01);
10928}
10929
10930static void alc267_quanta_il1_automute(struct hda_codec *codec)
10931{
10932 alc267_quanta_il1_hp_automute(codec);
10933 alc267_quanta_il1_mic_automute(codec);
10934}
10935
10936static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
10937 unsigned int res)
10938{
10939 switch (res >> 26) {
10940 case ALC880_HP_EVENT:
10941 alc267_quanta_il1_hp_automute(codec);
10942 break;
10943 case ALC880_MIC_EVENT:
10944 alc267_quanta_il1_mic_automute(codec);
10945 break;
10946 }
10947}
10948
Kailang Yanga361d842007-06-05 12:30:55 +020010949/*
10950 * generic initialization of ADC, input mixers and output mixers
10951 */
10952static struct hda_verb alc268_base_init_verbs[] = {
10953 /* Unmute DAC0-1 and set vol = 0 */
10954 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10955 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10956 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10957 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10958 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10959 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10960
10961 /*
10962 * Set up output mixers (0x0c - 0x0e)
10963 */
10964 /* set vol=0 to output mixers */
10965 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10966 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10967 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10968 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
10969
10970 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10971 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10972
10973 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10974 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10975 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10976 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10977 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10978 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10979 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10980 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10981
10982 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10983 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10984 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10985 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10986 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10987 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10988 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010989
10990 /* set PCBEEP vol = 0, mute connections */
10991 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10992 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10993 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010994
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010995 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020010996
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010997 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10998 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10999 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11000 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011001
Kailang Yanga361d842007-06-05 12:30:55 +020011002 { }
11003};
11004
11005/*
11006 * generic initialization of ADC, input mixers and output mixers
11007 */
11008static struct hda_verb alc268_volume_init_verbs[] = {
11009 /* set output DAC */
11010 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11011 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11012 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11013 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11014
11015 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11016 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11017 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11018 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11019 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11020
11021 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11022 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11023 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11024 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11025 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11026
11027 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11028 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11029 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11030 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11031
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011032 /* set PCBEEP vol = 0, mute connections */
11033 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11034 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11035 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011036
11037 { }
11038};
11039
11040#define alc268_mux_enum_info alc_mux_enum_info
11041#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010011042#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +020011043
11044static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11045 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11046 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11047 {
11048 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11049 /* The multiple "Capture Source" controls confuse alsamixer
11050 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011051 */
11052 /* .name = "Capture Source", */
11053 .name = "Input Source",
11054 .count = 1,
11055 .info = alc268_mux_enum_info,
11056 .get = alc268_mux_enum_get,
11057 .put = alc268_mux_enum_put,
11058 },
11059 { } /* end */
11060};
11061
11062static struct snd_kcontrol_new alc268_capture_mixer[] = {
11063 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11064 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11065 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11066 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11067 {
11068 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11069 /* The multiple "Capture Source" controls confuse alsamixer
11070 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011071 */
11072 /* .name = "Capture Source", */
11073 .name = "Input Source",
11074 .count = 2,
11075 .info = alc268_mux_enum_info,
11076 .get = alc268_mux_enum_get,
11077 .put = alc268_mux_enum_put,
11078 },
11079 { } /* end */
11080};
11081
11082static struct hda_input_mux alc268_capture_source = {
11083 .num_items = 4,
11084 .items = {
11085 { "Mic", 0x0 },
11086 { "Front Mic", 0x1 },
11087 { "Line", 0x2 },
11088 { "CD", 0x3 },
11089 },
11090};
11091
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011092static struct hda_input_mux alc268_acer_capture_source = {
11093 .num_items = 3,
11094 .items = {
11095 { "Mic", 0x0 },
11096 { "Internal Mic", 0x6 },
11097 { "Line", 0x2 },
11098 },
11099};
11100
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011101#ifdef CONFIG_SND_DEBUG
11102static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011103 /* Volume widgets */
11104 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11105 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11106 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11107 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11108 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11109 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11110 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11111 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11112 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11113 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11114 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11115 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11116 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011117 /* The below appears problematic on some hardwares */
11118 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011119 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11120 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11121 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11122 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11123
11124 /* Modes for retasking pin widgets */
11125 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11126 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11127 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11128 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11129
11130 /* Controls for GPIO pins, assuming they are configured as outputs */
11131 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11132 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11133 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11134 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11135
11136 /* Switches to allow the digital SPDIF output pin to be enabled.
11137 * The ALC268 does not have an SPDIF input.
11138 */
11139 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11140
11141 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11142 * this output to turn on an external amplifier.
11143 */
11144 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11145 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11146
11147 { } /* end */
11148};
11149#endif
11150
Kailang Yanga361d842007-06-05 12:30:55 +020011151/* create input playback/capture controls for the given pin */
11152static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11153 const char *ctlname, int idx)
11154{
11155 char name[32];
11156 int err;
11157
11158 sprintf(name, "%s Playback Volume", ctlname);
11159 if (nid == 0x14) {
11160 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11161 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11162 HDA_OUTPUT));
11163 if (err < 0)
11164 return err;
11165 } else if (nid == 0x15) {
11166 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11167 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11168 HDA_OUTPUT));
11169 if (err < 0)
11170 return err;
11171 } else
11172 return -1;
11173 sprintf(name, "%s Playback Switch", ctlname);
11174 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11175 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11176 if (err < 0)
11177 return err;
11178 return 0;
11179}
11180
11181/* add playback controls from the parsed DAC table */
11182static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11183 const struct auto_pin_cfg *cfg)
11184{
11185 hda_nid_t nid;
11186 int err;
11187
11188 spec->multiout.num_dacs = 2; /* only use one dac */
11189 spec->multiout.dac_nids = spec->private_dac_nids;
11190 spec->multiout.dac_nids[0] = 2;
11191 spec->multiout.dac_nids[1] = 3;
11192
11193 nid = cfg->line_out_pins[0];
11194 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011195 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011196
11197 nid = cfg->speaker_pins[0];
11198 if (nid == 0x1d) {
11199 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11200 "Speaker Playback Volume",
11201 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11202 if (err < 0)
11203 return err;
11204 }
11205 nid = cfg->hp_pins[0];
11206 if (nid)
11207 alc268_new_analog_output(spec, nid, "Headphone", 0);
11208
11209 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11210 if (nid == 0x16) {
11211 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11212 "Mono Playback Switch",
11213 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11214 if (err < 0)
11215 return err;
11216 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011217 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011218}
11219
11220/* create playback/capture controls for input pins */
11221static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11222 const struct auto_pin_cfg *cfg)
11223{
11224 struct hda_input_mux *imux = &spec->private_imux;
11225 int i, idx1;
11226
11227 for (i = 0; i < AUTO_PIN_LAST; i++) {
11228 switch(cfg->input_pins[i]) {
11229 case 0x18:
11230 idx1 = 0; /* Mic 1 */
11231 break;
11232 case 0x19:
11233 idx1 = 1; /* Mic 2 */
11234 break;
11235 case 0x1a:
11236 idx1 = 2; /* Line In */
11237 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011238 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011239 idx1 = 3; /* CD */
11240 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011241 case 0x12:
11242 case 0x13:
11243 idx1 = 6; /* digital mics */
11244 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011245 default:
11246 continue;
11247 }
11248 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11249 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011250 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011251 }
11252 return 0;
11253}
11254
11255static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11256{
11257 struct alc_spec *spec = codec->spec;
11258 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11259 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11260 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11261 unsigned int dac_vol1, dac_vol2;
11262
11263 if (speaker_nid) {
11264 snd_hda_codec_write(codec, speaker_nid, 0,
11265 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11266 snd_hda_codec_write(codec, 0x0f, 0,
11267 AC_VERB_SET_AMP_GAIN_MUTE,
11268 AMP_IN_UNMUTE(1));
11269 snd_hda_codec_write(codec, 0x10, 0,
11270 AC_VERB_SET_AMP_GAIN_MUTE,
11271 AMP_IN_UNMUTE(1));
11272 } else {
11273 snd_hda_codec_write(codec, 0x0f, 0,
11274 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11275 snd_hda_codec_write(codec, 0x10, 0,
11276 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11277 }
11278
11279 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011280 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011281 dac_vol2 = AMP_OUT_ZERO;
11282 else if (line_nid == 0x15)
11283 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011284 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011285 dac_vol2 = AMP_OUT_ZERO;
11286 else if (hp_nid == 0x15)
11287 dac_vol1 = AMP_OUT_ZERO;
11288 if (line_nid != 0x16 || hp_nid != 0x16 ||
11289 spec->autocfg.line_out_pins[1] != 0x16 ||
11290 spec->autocfg.line_out_pins[2] != 0x16)
11291 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11292
11293 snd_hda_codec_write(codec, 0x02, 0,
11294 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11295 snd_hda_codec_write(codec, 0x03, 0,
11296 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11297}
11298
11299/* pcm configuration: identiacal with ALC880 */
11300#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11301#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011302#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011303#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11304
11305/*
11306 * BIOS auto configuration
11307 */
11308static int alc268_parse_auto_config(struct hda_codec *codec)
11309{
11310 struct alc_spec *spec = codec->spec;
11311 int err;
11312 static hda_nid_t alc268_ignore[] = { 0 };
11313
11314 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11315 alc268_ignore);
11316 if (err < 0)
11317 return err;
11318 if (!spec->autocfg.line_outs)
11319 return 0; /* can't find valid BIOS pin config */
11320
11321 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11322 if (err < 0)
11323 return err;
11324 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11325 if (err < 0)
11326 return err;
11327
11328 spec->multiout.max_channels = 2;
11329
11330 /* digital only support output */
11331 if (spec->autocfg.dig_out_pin)
11332 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11333
11334 if (spec->kctl_alloc)
11335 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11336
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011337 if (spec->autocfg.speaker_pins[0] != 0x1d)
11338 spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
11339
Kailang Yanga361d842007-06-05 12:30:55 +020011340 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
11341 spec->num_mux_defs = 1;
11342 spec->input_mux = &spec->private_imux;
11343
Takashi Iwai776e1842007-08-29 15:07:11 +020011344 err = alc_auto_add_mic_boost(codec);
11345 if (err < 0)
11346 return err;
11347
Kailang Yanga361d842007-06-05 12:30:55 +020011348 return 1;
11349}
11350
11351#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11352#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11353#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11354
11355/* init callback for auto-configuration model -- overriding the default init */
11356static void alc268_auto_init(struct hda_codec *codec)
11357{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011358 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011359 alc268_auto_init_multi_out(codec);
11360 alc268_auto_init_hp_out(codec);
11361 alc268_auto_init_mono_speaker_out(codec);
11362 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011363 if (spec->unsol_event)
11364 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011365}
11366
11367/*
11368 * configuration and preset
11369 */
11370static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011371 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011372 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011373 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011374 [ALC268_ACER] = "acer",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011375 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011376 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011377 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011378#ifdef CONFIG_SND_DEBUG
11379 [ALC268_TEST] = "test",
11380#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011381 [ALC268_AUTO] = "auto",
11382};
11383
11384static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011385 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011386 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011387 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011388 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011389 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011390 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11391 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011392 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011393 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011394 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011395 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011396 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011397 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011398 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011399 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011400 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011401 {}
11402};
11403
11404static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011405 [ALC267_QUANTA_IL1] = {
11406 .mixers = { alc267_quanta_il1_mixer },
11407 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11408 alc267_quanta_il1_verbs },
11409 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11410 .dac_nids = alc268_dac_nids,
11411 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11412 .adc_nids = alc268_adc_nids_alt,
11413 .hp_nid = 0x03,
11414 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11415 .channel_mode = alc268_modes,
11416 .input_mux = &alc268_capture_source,
11417 .unsol_event = alc267_quanta_il1_unsol_event,
11418 .init_hook = alc267_quanta_il1_automute,
11419 },
Kailang Yanga361d842007-06-05 12:30:55 +020011420 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011421 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11422 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011423 .init_verbs = { alc268_base_init_verbs },
11424 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11425 .dac_nids = alc268_dac_nids,
11426 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11427 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011428 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011429 .hp_nid = 0x03,
11430 .dig_out_nid = ALC268_DIGOUT_NID,
11431 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11432 .channel_mode = alc268_modes,
11433 .input_mux = &alc268_capture_source,
11434 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011435 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011436 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11437 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011438 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11439 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011440 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11441 .dac_nids = alc268_dac_nids,
11442 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11443 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011444 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011445 .hp_nid = 0x03,
11446 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11447 .channel_mode = alc268_modes,
11448 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011449 .unsol_event = alc268_toshiba_unsol_event,
11450 .init_hook = alc268_toshiba_automute,
11451 },
11452 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011453 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11454 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011455 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11456 alc268_acer_verbs },
11457 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11458 .dac_nids = alc268_dac_nids,
11459 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11460 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011461 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011462 .hp_nid = 0x02,
11463 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11464 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011465 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011466 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011467 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011468 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011469 [ALC268_ACER_ASPIRE_ONE] = {
11470 .mixers = { alc268_acer_aspire_one_mixer,
11471 alc268_capture_alt_mixer },
11472 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11473 alc268_acer_aspire_one_verbs },
11474 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11475 .dac_nids = alc268_dac_nids,
11476 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11477 .adc_nids = alc268_adc_nids_alt,
11478 .capsrc_nids = alc268_capsrc_nids,
11479 .hp_nid = 0x03,
11480 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11481 .channel_mode = alc268_modes,
11482 .input_mux = &alc268_acer_lc_capture_source,
11483 .unsol_event = alc268_acer_lc_unsol_event,
11484 .init_hook = alc268_acer_lc_init_hook,
11485 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011486 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011487 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011488 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11489 alc268_dell_verbs },
11490 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11491 .dac_nids = alc268_dac_nids,
11492 .hp_nid = 0x02,
11493 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11494 .channel_mode = alc268_modes,
11495 .unsol_event = alc268_dell_unsol_event,
11496 .init_hook = alc268_dell_init_hook,
11497 .input_mux = &alc268_capture_source,
11498 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011499 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011500 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11501 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011502 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11503 alc268_toshiba_verbs },
11504 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11505 .dac_nids = alc268_dac_nids,
11506 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11507 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011508 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011509 .hp_nid = 0x03,
11510 .dig_out_nid = ALC268_DIGOUT_NID,
11511 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11512 .channel_mode = alc268_modes,
11513 .input_mux = &alc268_capture_source,
11514 .unsol_event = alc268_toshiba_unsol_event,
11515 .init_hook = alc268_toshiba_automute
11516 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011517#ifdef CONFIG_SND_DEBUG
11518 [ALC268_TEST] = {
11519 .mixers = { alc268_test_mixer, alc268_capture_mixer },
11520 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11521 alc268_volume_init_verbs },
11522 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11523 .dac_nids = alc268_dac_nids,
11524 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11525 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011526 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011527 .hp_nid = 0x03,
11528 .dig_out_nid = ALC268_DIGOUT_NID,
11529 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11530 .channel_mode = alc268_modes,
11531 .input_mux = &alc268_capture_source,
11532 },
11533#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011534};
11535
11536static int patch_alc268(struct hda_codec *codec)
11537{
11538 struct alc_spec *spec;
11539 int board_config;
11540 int err;
11541
11542 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
11543 if (spec == NULL)
11544 return -ENOMEM;
11545
11546 codec->spec = spec;
11547
11548 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
11549 alc268_models,
11550 alc268_cfg_tbl);
11551
11552 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
11553 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
11554 "trying auto-probe from BIOS...\n");
11555 board_config = ALC268_AUTO;
11556 }
11557
11558 if (board_config == ALC268_AUTO) {
11559 /* automatic parse from the BIOS config */
11560 err = alc268_parse_auto_config(codec);
11561 if (err < 0) {
11562 alc_free(codec);
11563 return err;
11564 } else if (!err) {
11565 printk(KERN_INFO
11566 "hda_codec: Cannot set up configuration "
11567 "from BIOS. Using base mode...\n");
11568 board_config = ALC268_3ST;
11569 }
11570 }
11571
11572 if (board_config != ALC268_AUTO)
11573 setup_preset(spec, &alc268_presets[board_config]);
11574
Kailang Yang2f893282008-05-27 12:14:47 +020011575 if (codec->vendor_id == 0x10ec0267) {
11576 spec->stream_name_analog = "ALC267 Analog";
11577 spec->stream_name_digital = "ALC267 Digital";
11578 } else {
11579 spec->stream_name_analog = "ALC268 Analog";
11580 spec->stream_name_digital = "ALC268 Digital";
11581 }
11582
Kailang Yanga361d842007-06-05 12:30:55 +020011583 spec->stream_analog_playback = &alc268_pcm_analog_playback;
11584 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010011585 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020011586
Kailang Yanga361d842007-06-05 12:30:55 +020011587 spec->stream_digital_playback = &alc268_pcm_digital_playback;
11588
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011589 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
11590 /* override the amp caps for beep generator */
11591 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
11592 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
11593 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
11594 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
11595 (0 << AC_AMPCAP_MUTE_SHIFT));
11596
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011597 if (!spec->adc_nids && spec->input_mux) {
11598 /* check whether NID 0x07 is valid */
11599 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010011600 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020011601
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011602 /* get type */
11603 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010011604 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011605 spec->adc_nids = alc268_adc_nids_alt;
11606 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
11607 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020011608 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011609 spec->num_mixers++;
11610 } else {
11611 spec->adc_nids = alc268_adc_nids;
11612 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
11613 spec->mixers[spec->num_mixers] =
11614 alc268_capture_mixer;
11615 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020011616 }
Takashi Iwaie1406342008-02-11 18:32:32 +010011617 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010011618 /* set default input source */
11619 for (i = 0; i < spec->num_adc_nids; i++)
11620 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
11621 0, AC_VERB_SET_CONNECT_SEL,
11622 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020011623 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010011624
11625 spec->vmaster_nid = 0x02;
11626
Kailang Yanga361d842007-06-05 12:30:55 +020011627 codec->patch_ops = alc_patch_ops;
11628 if (board_config == ALC268_AUTO)
11629 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020011630
Kailang Yanga361d842007-06-05 12:30:55 +020011631 return 0;
11632}
11633
11634/*
Kailang Yangf6a92242007-12-13 16:52:54 +010011635 * ALC269 channel source setting (2 channel)
11636 */
11637#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
11638
11639#define alc269_dac_nids alc260_dac_nids
11640
11641static hda_nid_t alc269_adc_nids[1] = {
11642 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020011643 0x08,
11644};
11645
Takashi Iwaie01bf502008-08-21 16:25:07 +020011646static hda_nid_t alc269_capsrc_nids[1] = {
11647 0x23,
11648};
11649
11650/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
11651 * not a mux!
11652 */
11653
Kailang Yangf53281e2008-07-18 12:36:43 +020011654static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
11655 .num_items = 2,
11656 .items = {
11657 { "i-Mic", 0x5 },
11658 { "e-Mic", 0x0 },
11659 },
11660};
11661
11662static struct hda_input_mux alc269_eeepc_amic_capture_source = {
11663 .num_items = 2,
11664 .items = {
11665 { "i-Mic", 0x1 },
11666 { "e-Mic", 0x0 },
11667 },
Kailang Yangf6a92242007-12-13 16:52:54 +010011668};
11669
11670#define alc269_modes alc260_modes
11671#define alc269_capture_source alc880_lg_lw_capture_source
11672
11673static struct snd_kcontrol_new alc269_base_mixer[] = {
11674 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11675 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11676 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11677 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11678 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11679 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020011680 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11681 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011682 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11683 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11684 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11685 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11686 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11687 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
11688 { } /* end */
11689};
11690
Kailang Yang60db6b52008-08-26 13:13:00 +020011691static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11692 /* output mixer control */
11693 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11694 {
11695 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11696 .name = "Master Playback Switch",
11697 .info = snd_hda_mixer_amp_switch_info,
11698 .get = snd_hda_mixer_amp_switch_get,
11699 .put = alc268_acer_master_sw_put,
11700 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11701 },
11702 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11703 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11704 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11705 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11706 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11707 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11708 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11709 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11710 { }
11711};
11712
Kailang Yangf53281e2008-07-18 12:36:43 +020011713/* bind volumes of both NID 0x0c and 0x0d */
11714static struct hda_bind_ctls alc269_epc_bind_vol = {
11715 .ops = &snd_hda_bind_vol,
11716 .values = {
11717 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11718 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11719 0
11720 },
11721};
11722
11723static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
11724 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11725 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
11726 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11727 { } /* end */
11728};
11729
Kailang Yangf6a92242007-12-13 16:52:54 +010011730/* capture mixer elements */
11731static struct snd_kcontrol_new alc269_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020011732 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11733 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011734 {
11735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11736 /* The multiple "Capture Source" controls confuse alsamixer
11737 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010011738 */
11739 /* .name = "Capture Source", */
11740 .name = "Input Source",
11741 .count = 1,
11742 .info = alc_mux_enum_info,
11743 .get = alc_mux_enum_get,
11744 .put = alc_mux_enum_put,
11745 },
11746 { } /* end */
11747};
11748
Kailang Yangf53281e2008-07-18 12:36:43 +020011749/* capture mixer elements */
11750static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
11751 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11752 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11753 { } /* end */
11754};
11755
Takashi Iwai2005af22008-08-20 18:38:26 +020011756/* beep control */
11757static struct snd_kcontrol_new alc269_beep_mixer[] = {
11758 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11759 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
11760 { } /* end */
11761};
11762
Kailang Yang60db6b52008-08-26 13:13:00 +020011763static struct hda_verb alc269_quanta_fl1_verbs[] = {
11764 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11765 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11766 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11767 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11768 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11769 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11770 { }
11771};
11772
11773/* toggle speaker-output according to the hp-jack state */
11774static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11775{
11776 unsigned int present;
11777 unsigned char bits;
11778
11779 present = snd_hda_codec_read(codec, 0x15, 0,
11780 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11781 bits = present ? AMP_IN_MUTE(0) : 0;
11782 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11783 AMP_IN_MUTE(0), bits);
11784 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11785 AMP_IN_MUTE(0), bits);
11786
11787 snd_hda_codec_write(codec, 0x20, 0,
11788 AC_VERB_SET_COEF_INDEX, 0x0c);
11789 snd_hda_codec_write(codec, 0x20, 0,
11790 AC_VERB_SET_PROC_COEF, 0x680);
11791
11792 snd_hda_codec_write(codec, 0x20, 0,
11793 AC_VERB_SET_COEF_INDEX, 0x0c);
11794 snd_hda_codec_write(codec, 0x20, 0,
11795 AC_VERB_SET_PROC_COEF, 0x480);
11796}
11797
11798static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11799{
11800 unsigned int present;
11801
11802 present = snd_hda_codec_read(codec, 0x18, 0,
11803 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11804 snd_hda_codec_write(codec, 0x23, 0,
11805 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11806}
11807
11808static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11809 unsigned int res)
11810{
11811 if ((res >> 26) == ALC880_HP_EVENT)
11812 alc269_quanta_fl1_speaker_automute(codec);
11813 if ((res >> 26) == ALC880_MIC_EVENT)
11814 alc269_quanta_fl1_mic_automute(codec);
11815}
11816
11817static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11818{
11819 alc269_quanta_fl1_speaker_automute(codec);
11820 alc269_quanta_fl1_mic_automute(codec);
11821}
11822
11823static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11824 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11825 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
11826 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11827 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
11828 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11829 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11830 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11831 {}
11832};
11833
11834static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
11835 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11836 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
11837 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11838 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
11839 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11840 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11841 {}
11842};
11843
11844/* toggle speaker-output according to the hp-jack state */
11845static void alc269_speaker_automute(struct hda_codec *codec)
11846{
11847 unsigned int present;
11848 unsigned char bits;
11849
11850 present = snd_hda_codec_read(codec, 0x15, 0,
11851 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11852 bits = present ? AMP_IN_MUTE(0) : 0;
11853 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11854 AMP_IN_MUTE(0), bits);
11855 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11856 AMP_IN_MUTE(0), bits);
11857}
11858
11859static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
11860{
11861 unsigned int present;
11862
11863 present = snd_hda_codec_read(codec, 0x18, 0,
11864 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11865 snd_hda_codec_write(codec, 0x23, 0,
11866 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
11867}
11868
11869static void alc269_eeepc_amic_automute(struct hda_codec *codec)
11870{
11871 unsigned int present;
11872
11873 present = snd_hda_codec_read(codec, 0x18, 0,
11874 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11875 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11876 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
11877 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11878 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
11879}
11880
11881/* unsolicited event for HP jack sensing */
11882static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
11883 unsigned int res)
11884{
11885 if ((res >> 26) == ALC880_HP_EVENT)
11886 alc269_speaker_automute(codec);
11887
11888 if ((res >> 26) == ALC880_MIC_EVENT)
11889 alc269_eeepc_dmic_automute(codec);
11890}
11891
11892static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
11893{
11894 alc269_speaker_automute(codec);
11895 alc269_eeepc_dmic_automute(codec);
11896}
11897
11898/* unsolicited event for HP jack sensing */
11899static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
11900 unsigned int res)
11901{
11902 if ((res >> 26) == ALC880_HP_EVENT)
11903 alc269_speaker_automute(codec);
11904
11905 if ((res >> 26) == ALC880_MIC_EVENT)
11906 alc269_eeepc_amic_automute(codec);
11907}
11908
11909static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
11910{
11911 alc269_speaker_automute(codec);
11912 alc269_eeepc_amic_automute(codec);
11913}
11914
Kailang Yangf6a92242007-12-13 16:52:54 +010011915/*
11916 * generic initialization of ADC, input mixers and output mixers
11917 */
11918static struct hda_verb alc269_init_verbs[] = {
11919 /*
11920 * Unmute ADC0 and set the default input to mic-in
11921 */
Kailang Yang60db6b52008-08-26 13:13:00 +020011922 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011923
11924 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
11925 * analog-loopback mixer widget
11926 * Note: PASD motherboards uses the Line In 2 as the input for
11927 * front panel mic (mic 2)
11928 */
11929 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
11930 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11931 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11932 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11933 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11934 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11935
11936 /*
11937 * Set up output mixers (0x0c - 0x0e)
11938 */
11939 /* set vol=0 to output mixers */
11940 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11941 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11942
11943 /* set up input amps for analog loopback */
11944 /* Amp Indices: DAC = 0, mixer = 1 */
11945 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11946 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11947 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11948 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11949 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11950 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11951
11952 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11953 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11954 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11955 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11956 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11957 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11958 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11959
11960 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11961 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11962 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11963 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11964 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11965 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11966 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11967
11968 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11969 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11970
11971 /* FIXME: use matrix-type input source selection */
11972 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
11973 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020011974 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11975 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011976 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11977 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11978
11979 /* set EAPD */
11980 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11981 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11982 { }
11983};
11984
11985/* add playback controls from the parsed DAC table */
11986static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
11987 const struct auto_pin_cfg *cfg)
11988{
11989 hda_nid_t nid;
11990 int err;
11991
11992 spec->multiout.num_dacs = 1; /* only use one dac */
11993 spec->multiout.dac_nids = spec->private_dac_nids;
11994 spec->multiout.dac_nids[0] = 2;
11995
11996 nid = cfg->line_out_pins[0];
11997 if (nid) {
11998 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11999 "Front Playback Volume",
12000 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12001 if (err < 0)
12002 return err;
12003 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12004 "Front Playback Switch",
12005 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12006 if (err < 0)
12007 return err;
12008 }
12009
12010 nid = cfg->speaker_pins[0];
12011 if (nid) {
12012 if (!cfg->line_out_pins[0]) {
12013 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12014 "Speaker Playback Volume",
12015 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12016 HDA_OUTPUT));
12017 if (err < 0)
12018 return err;
12019 }
12020 if (nid == 0x16) {
12021 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12022 "Speaker Playback Switch",
12023 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12024 HDA_OUTPUT));
12025 if (err < 0)
12026 return err;
12027 } else {
12028 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12029 "Speaker Playback Switch",
12030 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12031 HDA_OUTPUT));
12032 if (err < 0)
12033 return err;
12034 }
12035 }
12036 nid = cfg->hp_pins[0];
12037 if (nid) {
12038 /* spec->multiout.hp_nid = 2; */
12039 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12040 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12041 "Headphone Playback Volume",
12042 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12043 HDA_OUTPUT));
12044 if (err < 0)
12045 return err;
12046 }
12047 if (nid == 0x16) {
12048 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12049 "Headphone Playback Switch",
12050 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12051 HDA_OUTPUT));
12052 if (err < 0)
12053 return err;
12054 } else {
12055 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12056 "Headphone Playback Switch",
12057 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12058 HDA_OUTPUT));
12059 if (err < 0)
12060 return err;
12061 }
12062 }
12063 return 0;
12064}
12065
12066#define alc269_auto_create_analog_input_ctls \
12067 alc880_auto_create_analog_input_ctls
12068
12069#ifdef CONFIG_SND_HDA_POWER_SAVE
12070#define alc269_loopbacks alc880_loopbacks
12071#endif
12072
12073/* pcm configuration: identiacal with ALC880 */
12074#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12075#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12076#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12077#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12078
12079/*
12080 * BIOS auto configuration
12081 */
12082static int alc269_parse_auto_config(struct hda_codec *codec)
12083{
12084 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012085 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012086 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12087
12088 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12089 alc269_ignore);
12090 if (err < 0)
12091 return err;
12092
12093 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12094 if (err < 0)
12095 return err;
12096 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12097 if (err < 0)
12098 return err;
12099
12100 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12101
12102 if (spec->autocfg.dig_out_pin)
12103 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12104
12105 if (spec->kctl_alloc)
12106 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12107
Takashi Iwai2005af22008-08-20 18:38:26 +020012108 /* create a beep mixer control if the pin 0x1d isn't assigned */
12109 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12110 if (spec->autocfg.input_pins[i] == 0x1d)
12111 break;
12112 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
12113 spec->mixers[spec->num_mixers++] = alc269_beep_mixer;
12114
Kailang Yangf6a92242007-12-13 16:52:54 +010012115 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
12116 spec->num_mux_defs = 1;
12117 spec->input_mux = &spec->private_imux;
Takashi Iwaie01bf502008-08-21 16:25:07 +020012118 /* set default input source */
12119 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12120 0, AC_VERB_SET_CONNECT_SEL,
12121 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012122
12123 err = alc_auto_add_mic_boost(codec);
12124 if (err < 0)
12125 return err;
12126
Kailang Yangf53281e2008-07-18 12:36:43 +020012127 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
12128 spec->num_mixers++;
12129
Kailang Yangf6a92242007-12-13 16:52:54 +010012130 return 1;
12131}
12132
12133#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12134#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12135#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12136
12137
12138/* init callback for auto-configuration model -- overriding the default init */
12139static void alc269_auto_init(struct hda_codec *codec)
12140{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012141 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012142 alc269_auto_init_multi_out(codec);
12143 alc269_auto_init_hp_out(codec);
12144 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012145 if (spec->unsol_event)
12146 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012147}
12148
12149/*
12150 * configuration and preset
12151 */
12152static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012153 [ALC269_BASIC] = "basic",
12154 [ALC269_QUANTA_FL1] = "Quanta",
12155 [ALC269_ASUS_EEEPC_P901] = "Asus_Epc_Dmic"
Kailang Yangf6a92242007-12-13 16:52:54 +010012156};
12157
12158static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012159 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012160 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12161 ALC269_ASUS_EEEPC_P703),
12162 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12163 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012164 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12165 ALC269_ASUS_EEEPC_P901),
Kailang Yangf6a92242007-12-13 16:52:54 +010012166 {}
12167};
12168
12169static struct alc_config_preset alc269_presets[] = {
12170 [ALC269_BASIC] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020012171 .mixers = { alc269_base_mixer, alc269_capture_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012172 .init_verbs = { alc269_init_verbs },
12173 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12174 .dac_nids = alc269_dac_nids,
12175 .hp_nid = 0x03,
12176 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12177 .channel_mode = alc269_modes,
12178 .input_mux = &alc269_capture_source,
12179 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012180 [ALC269_QUANTA_FL1] = {
12181 .mixers = { alc269_quanta_fl1_mixer },
12182 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12183 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12184 .dac_nids = alc269_dac_nids,
12185 .hp_nid = 0x03,
12186 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12187 .channel_mode = alc269_modes,
12188 .input_mux = &alc269_capture_source,
12189 .unsol_event = alc269_quanta_fl1_unsol_event,
12190 .init_hook = alc269_quanta_fl1_init_hook,
12191 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012192 [ALC269_ASUS_EEEPC_P703] = {
12193 .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
12194 .init_verbs = { alc269_init_verbs,
12195 alc269_eeepc_amic_init_verbs },
12196 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12197 .dac_nids = alc269_dac_nids,
12198 .hp_nid = 0x03,
12199 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12200 .channel_mode = alc269_modes,
12201 .input_mux = &alc269_eeepc_amic_capture_source,
12202 .unsol_event = alc269_eeepc_amic_unsol_event,
12203 .init_hook = alc269_eeepc_amic_inithook,
12204 },
12205 [ALC269_ASUS_EEEPC_P901] = {
12206 .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer},
12207 .init_verbs = { alc269_init_verbs,
12208 alc269_eeepc_dmic_init_verbs },
12209 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12210 .dac_nids = alc269_dac_nids,
12211 .hp_nid = 0x03,
12212 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12213 .channel_mode = alc269_modes,
12214 .input_mux = &alc269_eeepc_dmic_capture_source,
12215 .unsol_event = alc269_eeepc_dmic_unsol_event,
12216 .init_hook = alc269_eeepc_dmic_inithook,
12217 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012218};
12219
12220static int patch_alc269(struct hda_codec *codec)
12221{
12222 struct alc_spec *spec;
12223 int board_config;
12224 int err;
12225
12226 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12227 if (spec == NULL)
12228 return -ENOMEM;
12229
12230 codec->spec = spec;
12231
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012232 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12233
Kailang Yangf6a92242007-12-13 16:52:54 +010012234 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12235 alc269_models,
12236 alc269_cfg_tbl);
12237
12238 if (board_config < 0) {
12239 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12240 "trying auto-probe from BIOS...\n");
12241 board_config = ALC269_AUTO;
12242 }
12243
12244 if (board_config == ALC269_AUTO) {
12245 /* automatic parse from the BIOS config */
12246 err = alc269_parse_auto_config(codec);
12247 if (err < 0) {
12248 alc_free(codec);
12249 return err;
12250 } else if (!err) {
12251 printk(KERN_INFO
12252 "hda_codec: Cannot set up configuration "
12253 "from BIOS. Using base mode...\n");
12254 board_config = ALC269_BASIC;
12255 }
12256 }
12257
12258 if (board_config != ALC269_AUTO)
12259 setup_preset(spec, &alc269_presets[board_config]);
12260
12261 spec->stream_name_analog = "ALC269 Analog";
12262 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12263 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12264
12265 spec->stream_name_digital = "ALC269 Digital";
12266 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12267 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12268
12269 spec->adc_nids = alc269_adc_nids;
12270 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012271 spec->capsrc_nids = alc269_capsrc_nids;
Kailang Yangf6a92242007-12-13 16:52:54 +010012272
12273 codec->patch_ops = alc_patch_ops;
12274 if (board_config == ALC269_AUTO)
12275 spec->init_hook = alc269_auto_init;
12276#ifdef CONFIG_SND_HDA_POWER_SAVE
12277 if (!spec->loopback.amplist)
12278 spec->loopback.amplist = alc269_loopbacks;
12279#endif
12280
12281 return 0;
12282}
12283
12284/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012285 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12286 */
12287
12288/*
12289 * set the path ways for 2 channel output
12290 * need to set the codec line out and mic 1 pin widgets to inputs
12291 */
12292static struct hda_verb alc861_threestack_ch2_init[] = {
12293 /* set pin widget 1Ah (line in) for input */
12294 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012295 /* set pin widget 18h (mic1/2) for input, for mic also enable
12296 * the vref
12297 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012298 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12299
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012300 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12301#if 0
12302 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12303 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12304#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012305 { } /* end */
12306};
12307/*
12308 * 6ch mode
12309 * need to set the codec line out and mic 1 pin widgets to outputs
12310 */
12311static struct hda_verb alc861_threestack_ch6_init[] = {
12312 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12313 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12314 /* set pin widget 18h (mic1) for output (CLFE)*/
12315 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12316
12317 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012318 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012319
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012320 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12321#if 0
12322 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12323 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12324#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012325 { } /* end */
12326};
12327
12328static struct hda_channel_mode alc861_threestack_modes[2] = {
12329 { 2, alc861_threestack_ch2_init },
12330 { 6, alc861_threestack_ch6_init },
12331};
Takashi Iwai22309c32006-08-09 16:57:28 +020012332/* Set mic1 as input and unmute the mixer */
12333static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
12334 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12335 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12336 { } /* end */
12337};
12338/* Set mic1 as output and mute mixer */
12339static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
12340 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12341 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12342 { } /* end */
12343};
12344
12345static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
12346 { 2, alc861_uniwill_m31_ch2_init },
12347 { 4, alc861_uniwill_m31_ch4_init },
12348};
Kailang Yangdf694da2005-12-05 19:42:22 +010012349
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012350/* Set mic1 and line-in as input and unmute the mixer */
12351static struct hda_verb alc861_asus_ch2_init[] = {
12352 /* set pin widget 1Ah (line in) for input */
12353 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012354 /* set pin widget 18h (mic1/2) for input, for mic also enable
12355 * the vref
12356 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012357 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12358
12359 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12360#if 0
12361 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12362 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12363#endif
12364 { } /* end */
12365};
12366/* Set mic1 nad line-in as output and mute mixer */
12367static struct hda_verb alc861_asus_ch6_init[] = {
12368 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12369 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12370 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12371 /* set pin widget 18h (mic1) for output (CLFE)*/
12372 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12373 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12374 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
12375 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
12376
12377 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12378#if 0
12379 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12380 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12381#endif
12382 { } /* end */
12383};
12384
12385static struct hda_channel_mode alc861_asus_modes[2] = {
12386 { 2, alc861_asus_ch2_init },
12387 { 6, alc861_asus_ch6_init },
12388};
12389
Kailang Yangdf694da2005-12-05 19:42:22 +010012390/* patch-ALC861 */
12391
12392static struct snd_kcontrol_new alc861_base_mixer[] = {
12393 /* output mixer control */
12394 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12395 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12396 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12397 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12398 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12399
12400 /*Input mixer control */
12401 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12402 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12403 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12404 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12405 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12406 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12407 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12408 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12409 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12410 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012411
Kailang Yangdf694da2005-12-05 19:42:22 +010012412 /* Capture mixer control */
12413 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12414 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12415 {
12416 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12417 .name = "Capture Source",
12418 .count = 1,
12419 .info = alc_mux_enum_info,
12420 .get = alc_mux_enum_get,
12421 .put = alc_mux_enum_put,
12422 },
12423 { } /* end */
12424};
12425
12426static struct snd_kcontrol_new alc861_3ST_mixer[] = {
12427 /* output mixer control */
12428 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12429 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12430 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12431 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12432 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12433
12434 /* Input mixer control */
12435 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12436 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12437 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12438 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12439 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12440 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12441 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12442 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12443 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12444 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012445
Kailang Yangdf694da2005-12-05 19:42:22 +010012446 /* Capture mixer control */
12447 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12448 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12449 {
12450 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12451 .name = "Capture Source",
12452 .count = 1,
12453 .info = alc_mux_enum_info,
12454 .get = alc_mux_enum_get,
12455 .put = alc_mux_enum_put,
12456 },
12457 {
12458 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12459 .name = "Channel Mode",
12460 .info = alc_ch_mode_info,
12461 .get = alc_ch_mode_get,
12462 .put = alc_ch_mode_put,
12463 .private_value = ARRAY_SIZE(alc861_threestack_modes),
12464 },
12465 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012466};
12467
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012468static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012469 /* output mixer control */
12470 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12471 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12472 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020012473
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012474 /*Capture mixer control */
12475 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12476 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12477 {
12478 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12479 .name = "Capture Source",
12480 .count = 1,
12481 .info = alc_mux_enum_info,
12482 .get = alc_mux_enum_get,
12483 .put = alc_mux_enum_put,
12484 },
12485
12486 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012487};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012488
Takashi Iwai22309c32006-08-09 16:57:28 +020012489static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
12490 /* output mixer control */
12491 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12492 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12493 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12494 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12495 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12496
12497 /* Input mixer control */
12498 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12499 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12500 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12501 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12502 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12503 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12504 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12505 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12506 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012508
Takashi Iwai22309c32006-08-09 16:57:28 +020012509 /* Capture mixer control */
12510 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12511 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12512 {
12513 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12514 .name = "Capture Source",
12515 .count = 1,
12516 .info = alc_mux_enum_info,
12517 .get = alc_mux_enum_get,
12518 .put = alc_mux_enum_put,
12519 },
12520 {
12521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12522 .name = "Channel Mode",
12523 .info = alc_ch_mode_info,
12524 .get = alc_ch_mode_get,
12525 .put = alc_ch_mode_put,
12526 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
12527 },
12528 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012529};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012530
12531static struct snd_kcontrol_new alc861_asus_mixer[] = {
12532 /* output mixer control */
12533 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12534 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12535 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12536 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12537 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12538
12539 /* Input mixer control */
12540 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12541 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12542 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12543 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12544 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12545 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12546 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12547 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12548 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012549 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
12550
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012551 /* Capture mixer control */
12552 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12553 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12554 {
12555 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12556 .name = "Capture Source",
12557 .count = 1,
12558 .info = alc_mux_enum_info,
12559 .get = alc_mux_enum_get,
12560 .put = alc_mux_enum_put,
12561 },
12562 {
12563 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12564 .name = "Channel Mode",
12565 .info = alc_ch_mode_info,
12566 .get = alc_ch_mode_get,
12567 .put = alc_ch_mode_put,
12568 .private_value = ARRAY_SIZE(alc861_asus_modes),
12569 },
12570 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012571};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012572
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012573/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012574static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012575 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12576 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12577 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
12578 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
12579 { }
12580};
12581
Kailang Yangdf694da2005-12-05 19:42:22 +010012582/*
12583 * generic initialization of ADC, input mixers and output mixers
12584 */
12585static struct hda_verb alc861_base_init_verbs[] = {
12586 /*
12587 * Unmute ADC0 and set the default input to mic-in
12588 */
12589 /* port-A for surround (rear panel) */
12590 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12591 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
12592 /* port-B for mic-in (rear panel) with vref */
12593 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12594 /* port-C for line-in (rear panel) */
12595 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12596 /* port-D for Front */
12597 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12598 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12599 /* port-E for HP out (front panel) */
12600 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12601 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012602 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012603 /* port-F for mic-in (front panel) with vref */
12604 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12605 /* port-G for CLFE (rear panel) */
12606 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12607 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
12608 /* port-H for side (rear panel) */
12609 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12610 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
12611 /* CD-in */
12612 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12613 /* route front mic to ADC1*/
12614 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12615 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012616
Kailang Yangdf694da2005-12-05 19:42:22 +010012617 /* Unmute DAC0~3 & spdif out*/
12618 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12619 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12620 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12621 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012623
Kailang Yangdf694da2005-12-05 19:42:22 +010012624 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12625 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12626 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12627 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12628 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012629
Kailang Yangdf694da2005-12-05 19:42:22 +010012630 /* Unmute Stereo Mixer 15 */
12631 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12632 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12633 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012634 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012635
12636 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12637 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12638 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12639 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12640 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12641 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12642 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12643 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012644 /* hp used DAC 3 (Front) */
12645 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012646 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12647
12648 { }
12649};
12650
12651static struct hda_verb alc861_threestack_init_verbs[] = {
12652 /*
12653 * Unmute ADC0 and set the default input to mic-in
12654 */
12655 /* port-A for surround (rear panel) */
12656 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12657 /* port-B for mic-in (rear panel) with vref */
12658 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12659 /* port-C for line-in (rear panel) */
12660 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12661 /* port-D for Front */
12662 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12663 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12664 /* port-E for HP out (front panel) */
12665 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12666 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012667 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012668 /* port-F for mic-in (front panel) with vref */
12669 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12670 /* port-G for CLFE (rear panel) */
12671 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12672 /* port-H for side (rear panel) */
12673 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12674 /* CD-in */
12675 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12676 /* route front mic to ADC1*/
12677 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12678 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12679 /* Unmute DAC0~3 & spdif out*/
12680 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12681 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12682 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12683 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12684 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012685
Kailang Yangdf694da2005-12-05 19:42:22 +010012686 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12687 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12688 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12689 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12690 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012691
Kailang Yangdf694da2005-12-05 19:42:22 +010012692 /* Unmute Stereo Mixer 15 */
12693 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12694 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12695 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012696 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012697
12698 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12699 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12700 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12701 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12702 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12703 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12704 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12705 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012706 /* hp used DAC 3 (Front) */
12707 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012708 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12709 { }
12710};
Takashi Iwai22309c32006-08-09 16:57:28 +020012711
12712static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
12713 /*
12714 * Unmute ADC0 and set the default input to mic-in
12715 */
12716 /* port-A for surround (rear panel) */
12717 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12718 /* port-B for mic-in (rear panel) with vref */
12719 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12720 /* port-C for line-in (rear panel) */
12721 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12722 /* port-D for Front */
12723 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12724 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12725 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012726 /* this has to be set to VREF80 */
12727 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012728 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012729 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012730 /* port-F for mic-in (front panel) with vref */
12731 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12732 /* port-G for CLFE (rear panel) */
12733 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12734 /* port-H for side (rear panel) */
12735 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12736 /* CD-in */
12737 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12738 /* route front mic to ADC1*/
12739 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12740 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12741 /* Unmute DAC0~3 & spdif out*/
12742 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12743 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12744 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12745 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12746 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012747
Takashi Iwai22309c32006-08-09 16:57:28 +020012748 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12749 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12750 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12751 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12752 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012753
Takashi Iwai22309c32006-08-09 16:57:28 +020012754 /* Unmute Stereo Mixer 15 */
12755 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12756 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12757 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012758 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020012759
12760 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12761 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12762 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12763 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12764 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12765 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12766 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12767 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012768 /* hp used DAC 3 (Front) */
12769 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020012770 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12771 { }
12772};
12773
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012774static struct hda_verb alc861_asus_init_verbs[] = {
12775 /*
12776 * Unmute ADC0 and set the default input to mic-in
12777 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012778 /* port-A for surround (rear panel)
12779 * according to codec#0 this is the HP jack
12780 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012781 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
12782 /* route front PCM to HP */
12783 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
12784 /* port-B for mic-in (rear panel) with vref */
12785 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12786 /* port-C for line-in (rear panel) */
12787 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12788 /* port-D for Front */
12789 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12790 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12791 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012792 /* this has to be set to VREF80 */
12793 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012794 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012795 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012796 /* port-F for mic-in (front panel) with vref */
12797 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12798 /* port-G for CLFE (rear panel) */
12799 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12800 /* port-H for side (rear panel) */
12801 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12802 /* CD-in */
12803 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12804 /* route front mic to ADC1*/
12805 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12806 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12807 /* Unmute DAC0~3 & spdif out*/
12808 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12809 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12810 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12811 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12812 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12813 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12814 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12815 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12816 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12817 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012818
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012819 /* Unmute Stereo Mixer 15 */
12820 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12821 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12822 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012823 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012824
12825 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12826 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12827 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12828 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12829 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12830 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12831 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12832 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012833 /* hp used DAC 3 (Front) */
12834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012835 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12836 { }
12837};
12838
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012839/* additional init verbs for ASUS laptops */
12840static struct hda_verb alc861_asus_laptop_init_verbs[] = {
12841 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
12842 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
12843 { }
12844};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012845
Kailang Yangdf694da2005-12-05 19:42:22 +010012846/*
12847 * generic initialization of ADC, input mixers and output mixers
12848 */
12849static struct hda_verb alc861_auto_init_verbs[] = {
12850 /*
12851 * Unmute ADC0 and set the default input to mic-in
12852 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012853 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010012854 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012855
Kailang Yangdf694da2005-12-05 19:42:22 +010012856 /* Unmute DAC0~3 & spdif out*/
12857 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12858 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12859 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12860 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12861 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012862
Kailang Yangdf694da2005-12-05 19:42:22 +010012863 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12864 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12865 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12866 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12867 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012868
Kailang Yangdf694da2005-12-05 19:42:22 +010012869 /* Unmute Stereo Mixer 15 */
12870 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12871 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12872 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12873 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
12874
12875 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12876 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12877 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12878 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12879 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12880 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12881 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12882 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12883
12884 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12885 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012886 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12887 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012888 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12889 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012890 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12891 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012892
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012893 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012894
12895 { }
12896};
12897
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012898static struct hda_verb alc861_toshiba_init_verbs[] = {
12899 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012900
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012901 { }
12902};
12903
12904/* toggle speaker-output according to the hp-jack state */
12905static void alc861_toshiba_automute(struct hda_codec *codec)
12906{
12907 unsigned int present;
12908
12909 present = snd_hda_codec_read(codec, 0x0f, 0,
12910 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012911 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
12912 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
12913 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
12914 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012915}
12916
12917static void alc861_toshiba_unsol_event(struct hda_codec *codec,
12918 unsigned int res)
12919{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012920 if ((res >> 26) == ALC880_HP_EVENT)
12921 alc861_toshiba_automute(codec);
12922}
12923
Kailang Yangdf694da2005-12-05 19:42:22 +010012924/* pcm configuration: identiacal with ALC880 */
12925#define alc861_pcm_analog_playback alc880_pcm_analog_playback
12926#define alc861_pcm_analog_capture alc880_pcm_analog_capture
12927#define alc861_pcm_digital_playback alc880_pcm_digital_playback
12928#define alc861_pcm_digital_capture alc880_pcm_digital_capture
12929
12930
12931#define ALC861_DIGOUT_NID 0x07
12932
12933static struct hda_channel_mode alc861_8ch_modes[1] = {
12934 { 8, NULL }
12935};
12936
12937static hda_nid_t alc861_dac_nids[4] = {
12938 /* front, surround, clfe, side */
12939 0x03, 0x06, 0x05, 0x04
12940};
12941
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012942static hda_nid_t alc660_dac_nids[3] = {
12943 /* front, clfe, surround */
12944 0x03, 0x05, 0x06
12945};
12946
Kailang Yangdf694da2005-12-05 19:42:22 +010012947static hda_nid_t alc861_adc_nids[1] = {
12948 /* ADC0-2 */
12949 0x08,
12950};
12951
12952static struct hda_input_mux alc861_capture_source = {
12953 .num_items = 5,
12954 .items = {
12955 { "Mic", 0x0 },
12956 { "Front Mic", 0x3 },
12957 { "Line", 0x1 },
12958 { "CD", 0x4 },
12959 { "Mixer", 0x5 },
12960 },
12961};
12962
12963/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012964static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
12965 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012966{
12967 int i;
12968 hda_nid_t nid;
12969
12970 spec->multiout.dac_nids = spec->private_dac_nids;
12971 for (i = 0; i < cfg->line_outs; i++) {
12972 nid = cfg->line_out_pins[i];
12973 if (nid) {
12974 if (i >= ARRAY_SIZE(alc861_dac_nids))
12975 continue;
12976 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
12977 }
12978 }
12979 spec->multiout.num_dacs = cfg->line_outs;
12980 return 0;
12981}
12982
12983/* add playback controls from the parsed DAC table */
12984static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
12985 const struct auto_pin_cfg *cfg)
12986{
12987 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012988 static const char *chname[4] = {
12989 "Front", "Surround", NULL /*CLFE*/, "Side"
12990 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012991 hda_nid_t nid;
12992 int i, idx, err;
12993
12994 for (i = 0; i < cfg->line_outs; i++) {
12995 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012996 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010012997 continue;
12998 if (nid == 0x05) {
12999 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013000 err = add_control(spec, ALC_CTL_BIND_MUTE,
13001 "Center Playback Switch",
13002 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13003 HDA_OUTPUT));
13004 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013005 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013006 err = add_control(spec, ALC_CTL_BIND_MUTE,
13007 "LFE Playback Switch",
13008 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13009 HDA_OUTPUT));
13010 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013011 return err;
13012 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013013 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13014 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013015 if (nid == alc861_dac_nids[idx])
13016 break;
13017 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013018 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13019 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13020 HDA_OUTPUT));
13021 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013022 return err;
13023 }
13024 }
13025 return 0;
13026}
13027
13028static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13029{
13030 int err;
13031 hda_nid_t nid;
13032
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013033 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013034 return 0;
13035
13036 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13037 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013038 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13039 "Headphone Playback Switch",
13040 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13041 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013042 return err;
13043 spec->multiout.hp_nid = nid;
13044 }
13045 return 0;
13046}
13047
13048/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013049static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13050 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013051{
Kailang Yangdf694da2005-12-05 19:42:22 +010013052 struct hda_input_mux *imux = &spec->private_imux;
13053 int i, err, idx, idx1;
13054
13055 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013056 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013057 case 0x0c:
13058 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013059 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013060 break;
13061 case 0x0f:
13062 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013063 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013064 break;
13065 case 0x0d:
13066 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013067 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013068 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013069 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013070 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013071 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013072 break;
13073 case 0x11:
13074 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013075 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013076 break;
13077 default:
13078 continue;
13079 }
13080
Takashi Iwai4a471b72005-12-07 13:56:29 +010013081 err = new_analog_input(spec, cfg->input_pins[i],
13082 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013083 if (err < 0)
13084 return err;
13085
Takashi Iwai4a471b72005-12-07 13:56:29 +010013086 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013087 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013088 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013089 }
13090 return 0;
13091}
13092
13093static struct snd_kcontrol_new alc861_capture_mixer[] = {
13094 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13095 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13096
13097 {
13098 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13099 /* The multiple "Capture Source" controls confuse alsamixer
13100 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010013101 */
13102 /* .name = "Capture Source", */
13103 .name = "Input Source",
13104 .count = 1,
13105 .info = alc_mux_enum_info,
13106 .get = alc_mux_enum_get,
13107 .put = alc_mux_enum_put,
13108 },
13109 { } /* end */
13110};
13111
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013112static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13113 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013114 int pin_type, int dac_idx)
13115{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013116 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13117 pin_type);
13118 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13119 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013120}
13121
13122static void alc861_auto_init_multi_out(struct hda_codec *codec)
13123{
13124 struct alc_spec *spec = codec->spec;
13125 int i;
13126
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013127 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013128 for (i = 0; i < spec->autocfg.line_outs; i++) {
13129 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013130 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013131 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013132 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013133 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013134 }
13135}
13136
13137static void alc861_auto_init_hp_out(struct hda_codec *codec)
13138{
13139 struct alc_spec *spec = codec->spec;
13140 hda_nid_t pin;
13141
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013142 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013143 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013144 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13145 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013146 pin = spec->autocfg.speaker_pins[0];
13147 if (pin)
13148 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013149}
13150
13151static void alc861_auto_init_analog_input(struct hda_codec *codec)
13152{
13153 struct alc_spec *spec = codec->spec;
13154 int i;
13155
13156 for (i = 0; i < AUTO_PIN_LAST; i++) {
13157 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013158 if (nid >= 0x0c && nid <= 0x11) {
13159 snd_hda_codec_write(codec, nid, 0,
13160 AC_VERB_SET_PIN_WIDGET_CONTROL,
13161 i <= AUTO_PIN_FRONT_MIC ?
13162 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013163 }
13164 }
13165}
13166
13167/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013168/* return 1 if successful, 0 if the proper config is not found,
13169 * or a negative error code
13170 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013171static int alc861_parse_auto_config(struct hda_codec *codec)
13172{
13173 struct alc_spec *spec = codec->spec;
13174 int err;
13175 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13176
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013177 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13178 alc861_ignore);
13179 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013180 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013181 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013182 return 0; /* can't find valid BIOS pin config */
13183
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013184 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13185 if (err < 0)
13186 return err;
13187 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13188 if (err < 0)
13189 return err;
13190 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13191 if (err < 0)
13192 return err;
13193 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13194 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013195 return err;
13196
13197 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13198
13199 if (spec->autocfg.dig_out_pin)
13200 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13201
13202 if (spec->kctl_alloc)
13203 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13204
13205 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
13206
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013207 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010013208 spec->input_mux = &spec->private_imux;
13209
13210 spec->adc_nids = alc861_adc_nids;
13211 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
13212 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
13213 spec->num_mixers++;
13214
13215 return 1;
13216}
13217
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013218/* additional initialization for auto-configuration model */
13219static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013220{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013221 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013222 alc861_auto_init_multi_out(codec);
13223 alc861_auto_init_hp_out(codec);
13224 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013225 if (spec->unsol_event)
13226 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013227}
13228
Takashi Iwaicb53c622007-08-10 17:21:45 +020013229#ifdef CONFIG_SND_HDA_POWER_SAVE
13230static struct hda_amp_list alc861_loopbacks[] = {
13231 { 0x15, HDA_INPUT, 0 },
13232 { 0x15, HDA_INPUT, 1 },
13233 { 0x15, HDA_INPUT, 2 },
13234 { 0x15, HDA_INPUT, 3 },
13235 { } /* end */
13236};
13237#endif
13238
Kailang Yangdf694da2005-12-05 19:42:22 +010013239
13240/*
13241 * configuration and preset
13242 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013243static const char *alc861_models[ALC861_MODEL_LAST] = {
13244 [ALC861_3ST] = "3stack",
13245 [ALC660_3ST] = "3stack-660",
13246 [ALC861_3ST_DIG] = "3stack-dig",
13247 [ALC861_6ST_DIG] = "6stack-dig",
13248 [ALC861_UNIWILL_M31] = "uniwill-m31",
13249 [ALC861_TOSHIBA] = "toshiba",
13250 [ALC861_ASUS] = "asus",
13251 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13252 [ALC861_AUTO] = "auto",
13253};
13254
13255static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013256 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013257 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13258 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13259 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013260 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013261 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013262 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013263 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13264 * Any other models that need this preset?
13265 */
13266 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013267 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13268 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013269 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13270 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13271 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13272 /* FIXME: the below seems conflict */
13273 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13274 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13275 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013276 {}
13277};
13278
13279static struct alc_config_preset alc861_presets[] = {
13280 [ALC861_3ST] = {
13281 .mixers = { alc861_3ST_mixer },
13282 .init_verbs = { alc861_threestack_init_verbs },
13283 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13284 .dac_nids = alc861_dac_nids,
13285 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13286 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013287 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013288 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13289 .adc_nids = alc861_adc_nids,
13290 .input_mux = &alc861_capture_source,
13291 },
13292 [ALC861_3ST_DIG] = {
13293 .mixers = { alc861_base_mixer },
13294 .init_verbs = { alc861_threestack_init_verbs },
13295 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13296 .dac_nids = alc861_dac_nids,
13297 .dig_out_nid = ALC861_DIGOUT_NID,
13298 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13299 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013300 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013301 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13302 .adc_nids = alc861_adc_nids,
13303 .input_mux = &alc861_capture_source,
13304 },
13305 [ALC861_6ST_DIG] = {
13306 .mixers = { alc861_base_mixer },
13307 .init_verbs = { alc861_base_init_verbs },
13308 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13309 .dac_nids = alc861_dac_nids,
13310 .dig_out_nid = ALC861_DIGOUT_NID,
13311 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13312 .channel_mode = alc861_8ch_modes,
13313 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13314 .adc_nids = alc861_adc_nids,
13315 .input_mux = &alc861_capture_source,
13316 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013317 [ALC660_3ST] = {
13318 .mixers = { alc861_3ST_mixer },
13319 .init_verbs = { alc861_threestack_init_verbs },
13320 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13321 .dac_nids = alc660_dac_nids,
13322 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13323 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013324 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013325 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13326 .adc_nids = alc861_adc_nids,
13327 .input_mux = &alc861_capture_source,
13328 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013329 [ALC861_UNIWILL_M31] = {
13330 .mixers = { alc861_uniwill_m31_mixer },
13331 .init_verbs = { alc861_uniwill_m31_init_verbs },
13332 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13333 .dac_nids = alc861_dac_nids,
13334 .dig_out_nid = ALC861_DIGOUT_NID,
13335 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13336 .channel_mode = alc861_uniwill_m31_modes,
13337 .need_dac_fix = 1,
13338 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13339 .adc_nids = alc861_adc_nids,
13340 .input_mux = &alc861_capture_source,
13341 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013342 [ALC861_TOSHIBA] = {
13343 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013344 .init_verbs = { alc861_base_init_verbs,
13345 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013346 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13347 .dac_nids = alc861_dac_nids,
13348 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13349 .channel_mode = alc883_3ST_2ch_modes,
13350 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13351 .adc_nids = alc861_adc_nids,
13352 .input_mux = &alc861_capture_source,
13353 .unsol_event = alc861_toshiba_unsol_event,
13354 .init_hook = alc861_toshiba_automute,
13355 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013356 [ALC861_ASUS] = {
13357 .mixers = { alc861_asus_mixer },
13358 .init_verbs = { alc861_asus_init_verbs },
13359 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13360 .dac_nids = alc861_dac_nids,
13361 .dig_out_nid = ALC861_DIGOUT_NID,
13362 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13363 .channel_mode = alc861_asus_modes,
13364 .need_dac_fix = 1,
13365 .hp_nid = 0x06,
13366 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13367 .adc_nids = alc861_adc_nids,
13368 .input_mux = &alc861_capture_source,
13369 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013370 [ALC861_ASUS_LAPTOP] = {
13371 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13372 .init_verbs = { alc861_asus_init_verbs,
13373 alc861_asus_laptop_init_verbs },
13374 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13375 .dac_nids = alc861_dac_nids,
13376 .dig_out_nid = ALC861_DIGOUT_NID,
13377 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13378 .channel_mode = alc883_3ST_2ch_modes,
13379 .need_dac_fix = 1,
13380 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13381 .adc_nids = alc861_adc_nids,
13382 .input_mux = &alc861_capture_source,
13383 },
13384};
Kailang Yangdf694da2005-12-05 19:42:22 +010013385
13386
13387static int patch_alc861(struct hda_codec *codec)
13388{
13389 struct alc_spec *spec;
13390 int board_config;
13391 int err;
13392
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013393 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013394 if (spec == NULL)
13395 return -ENOMEM;
13396
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013397 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013398
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013399 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
13400 alc861_models,
13401 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013402
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013403 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013404 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
13405 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013406 board_config = ALC861_AUTO;
13407 }
13408
13409 if (board_config == ALC861_AUTO) {
13410 /* automatic parse from the BIOS config */
13411 err = alc861_parse_auto_config(codec);
13412 if (err < 0) {
13413 alc_free(codec);
13414 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013415 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013416 printk(KERN_INFO
13417 "hda_codec: Cannot set up configuration "
13418 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013419 board_config = ALC861_3ST_DIG;
13420 }
13421 }
13422
13423 if (board_config != ALC861_AUTO)
13424 setup_preset(spec, &alc861_presets[board_config]);
13425
13426 spec->stream_name_analog = "ALC861 Analog";
13427 spec->stream_analog_playback = &alc861_pcm_analog_playback;
13428 spec->stream_analog_capture = &alc861_pcm_analog_capture;
13429
13430 spec->stream_name_digital = "ALC861 Digital";
13431 spec->stream_digital_playback = &alc861_pcm_digital_playback;
13432 spec->stream_digital_capture = &alc861_pcm_digital_capture;
13433
Takashi Iwai2134ea42008-01-10 16:53:55 +010013434 spec->vmaster_nid = 0x03;
13435
Kailang Yangdf694da2005-12-05 19:42:22 +010013436 codec->patch_ops = alc_patch_ops;
13437 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013438 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013439#ifdef CONFIG_SND_HDA_POWER_SAVE
13440 if (!spec->loopback.amplist)
13441 spec->loopback.amplist = alc861_loopbacks;
13442#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013443
Kailang Yangdf694da2005-12-05 19:42:22 +010013444 return 0;
13445}
13446
13447/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013448 * ALC861-VD support
13449 *
13450 * Based on ALC882
13451 *
13452 * In addition, an independent DAC
13453 */
13454#define ALC861VD_DIGOUT_NID 0x06
13455
13456static hda_nid_t alc861vd_dac_nids[4] = {
13457 /* front, surr, clfe, side surr */
13458 0x02, 0x03, 0x04, 0x05
13459};
13460
13461/* dac_nids for ALC660vd are in a different order - according to
13462 * Realtek's driver.
13463 * This should probably tesult in a different mixer for 6stack models
13464 * of ALC660vd codecs, but for now there is only 3stack mixer
13465 * - and it is the same as in 861vd.
13466 * adc_nids in ALC660vd are (is) the same as in 861vd
13467 */
13468static hda_nid_t alc660vd_dac_nids[3] = {
13469 /* front, rear, clfe, rear_surr */
13470 0x02, 0x04, 0x03
13471};
13472
13473static hda_nid_t alc861vd_adc_nids[1] = {
13474 /* ADC0 */
13475 0x09,
13476};
13477
Takashi Iwaie1406342008-02-11 18:32:32 +010013478static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
13479
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013480/* input MUX */
13481/* FIXME: should be a matrix-type input source selection */
13482static struct hda_input_mux alc861vd_capture_source = {
13483 .num_items = 4,
13484 .items = {
13485 { "Mic", 0x0 },
13486 { "Front Mic", 0x1 },
13487 { "Line", 0x2 },
13488 { "CD", 0x4 },
13489 },
13490};
13491
Kailang Yang272a5272007-05-14 11:00:38 +020013492static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010013493 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020013494 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010013495 { "Ext Mic", 0x0 },
13496 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020013497 },
13498};
13499
Kailang Yangd1a991a2007-08-15 16:21:59 +020013500static struct hda_input_mux alc861vd_hp_capture_source = {
13501 .num_items = 2,
13502 .items = {
13503 { "Front Mic", 0x0 },
13504 { "ATAPI Mic", 0x1 },
13505 },
13506};
13507
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013508#define alc861vd_mux_enum_info alc_mux_enum_info
13509#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010013510/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
13511#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013512
13513/*
13514 * 2ch mode
13515 */
13516static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
13517 { 2, NULL }
13518};
13519
13520/*
13521 * 6ch mode
13522 */
13523static struct hda_verb alc861vd_6stack_ch6_init[] = {
13524 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13525 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13526 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13527 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13528 { } /* end */
13529};
13530
13531/*
13532 * 8ch mode
13533 */
13534static struct hda_verb alc861vd_6stack_ch8_init[] = {
13535 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13536 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13537 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13538 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13539 { } /* end */
13540};
13541
13542static struct hda_channel_mode alc861vd_6stack_modes[2] = {
13543 { 6, alc861vd_6stack_ch6_init },
13544 { 8, alc861vd_6stack_ch8_init },
13545};
13546
13547static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
13548 {
13549 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13550 .name = "Channel Mode",
13551 .info = alc_ch_mode_info,
13552 .get = alc_ch_mode_get,
13553 .put = alc_ch_mode_put,
13554 },
13555 { } /* end */
13556};
13557
13558static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
13559 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13560 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13561
13562 {
13563 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13564 /* The multiple "Capture Source" controls confuse alsamixer
13565 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013566 */
13567 /* .name = "Capture Source", */
13568 .name = "Input Source",
13569 .count = 1,
13570 .info = alc861vd_mux_enum_info,
13571 .get = alc861vd_mux_enum_get,
13572 .put = alc861vd_mux_enum_put,
13573 },
13574 { } /* end */
13575};
13576
13577/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13578 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13579 */
13580static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
13581 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13582 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13583
13584 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13585 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
13586
13587 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
13588 HDA_OUTPUT),
13589 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
13590 HDA_OUTPUT),
13591 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13592 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
13593
13594 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
13595 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
13596
13597 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13598
13599 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13600 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13601 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13602
13603 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13604 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13605 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13606
13607 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13608 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13609
13610 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13611 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13612
13613 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13614 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13615
13616 { } /* end */
13617};
13618
13619static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
13620 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13621 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13622
13623 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13624
13625 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13626 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13627 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13628
13629 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13630 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13631 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13632
13633 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13634 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13635
13636 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13637 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13638
13639 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13640 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13641
13642 { } /* end */
13643};
13644
Kailang Yangbdd148a2007-05-08 15:19:08 +020013645static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
13646 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13647 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
13648 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13649
13650 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13651
13652 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13653 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13654 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13655
13656 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13657 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13658 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13659
13660 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13661 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13662
13663 { } /* end */
13664};
13665
Tobin Davisb419f342008-03-07 11:57:51 +010013666/* Pin assignment: Speaker=0x14, HP = 0x15,
13667 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020013668 */
13669static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010013670 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13671 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013672 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13673 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010013674 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13675 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13676 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13677 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13678 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13679 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13680 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
13681 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013682 { } /* end */
13683};
13684
Kailang Yangd1a991a2007-08-15 16:21:59 +020013685/* Pin assignment: Speaker=0x14, Line-out = 0x15,
13686 * Front Mic=0x18, ATAPI Mic = 0x19,
13687 */
13688static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
13689 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13690 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13691 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13692 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
13693 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13694 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13695 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13696 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013697
Kailang Yangd1a991a2007-08-15 16:21:59 +020013698 { } /* end */
13699};
13700
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013701/*
13702 * generic initialization of ADC, input mixers and output mixers
13703 */
13704static struct hda_verb alc861vd_volume_init_verbs[] = {
13705 /*
13706 * Unmute ADC0 and set the default input to mic-in
13707 */
13708 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13709 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13710
13711 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
13712 * the analog-loopback mixer widget
13713 */
13714 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013715 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13716 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13717 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13718 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13719 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013720
13721 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020013722 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13723 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13724 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013725 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013726
13727 /*
13728 * Set up output mixers (0x02 - 0x05)
13729 */
13730 /* set vol=0 to output mixers */
13731 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13732 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13733 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13734 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13735
13736 /* set up input amps for analog loopback */
13737 /* Amp Indices: DAC = 0, mixer = 1 */
13738 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13739 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13740 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13741 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13742 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13743 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13744 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13745 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13746
13747 { }
13748};
13749
13750/*
13751 * 3-stack pin configuration:
13752 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
13753 */
13754static struct hda_verb alc861vd_3stack_init_verbs[] = {
13755 /*
13756 * Set pin mode and muting
13757 */
13758 /* set front pin widgets 0x14 for output */
13759 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13760 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13761 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13762
13763 /* Mic (rear) pin: input vref at 80% */
13764 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13765 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13766 /* Front Mic pin: input vref at 80% */
13767 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13768 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13769 /* Line In pin: input */
13770 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13771 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13772 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13773 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13774 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13775 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13776 /* CD pin widget for input */
13777 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13778
13779 { }
13780};
13781
13782/*
13783 * 6-stack pin configuration:
13784 */
13785static struct hda_verb alc861vd_6stack_init_verbs[] = {
13786 /*
13787 * Set pin mode and muting
13788 */
13789 /* set front pin widgets 0x14 for output */
13790 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13791 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13792 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13793
13794 /* Rear Pin: output 1 (0x0d) */
13795 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13796 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13797 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13798 /* CLFE Pin: output 2 (0x0e) */
13799 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13800 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13801 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
13802 /* Side Pin: output 3 (0x0f) */
13803 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13804 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13805 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
13806
13807 /* Mic (rear) pin: input vref at 80% */
13808 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13809 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13810 /* Front Mic pin: input vref at 80% */
13811 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13812 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13813 /* Line In pin: input */
13814 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13815 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13816 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13817 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13818 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13819 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13820 /* CD pin widget for input */
13821 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13822
13823 { }
13824};
13825
Kailang Yangbdd148a2007-05-08 15:19:08 +020013826static struct hda_verb alc861vd_eapd_verbs[] = {
13827 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13828 { }
13829};
13830
Kailang Yangf9423e72008-05-27 12:32:25 +020013831static struct hda_verb alc660vd_eapd_verbs[] = {
13832 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13833 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13834 { }
13835};
13836
Kailang Yangbdd148a2007-05-08 15:19:08 +020013837static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
13838 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13839 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13840 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
13841 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020013842 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020013843 {}
13844};
13845
13846/* toggle speaker-output according to the hp-jack state */
13847static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
13848{
13849 unsigned int present;
13850 unsigned char bits;
13851
13852 present = snd_hda_codec_read(codec, 0x1b, 0,
13853 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013854 bits = present ? HDA_AMP_MUTE : 0;
13855 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13856 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013857}
13858
13859static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
13860{
13861 unsigned int present;
13862 unsigned char bits;
13863
13864 present = snd_hda_codec_read(codec, 0x18, 0,
13865 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013866 bits = present ? HDA_AMP_MUTE : 0;
13867 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
13868 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013869}
13870
13871static void alc861vd_lenovo_automute(struct hda_codec *codec)
13872{
13873 alc861vd_lenovo_hp_automute(codec);
13874 alc861vd_lenovo_mic_automute(codec);
13875}
13876
13877static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
13878 unsigned int res)
13879{
13880 switch (res >> 26) {
13881 case ALC880_HP_EVENT:
13882 alc861vd_lenovo_hp_automute(codec);
13883 break;
13884 case ALC880_MIC_EVENT:
13885 alc861vd_lenovo_mic_automute(codec);
13886 break;
13887 }
13888}
13889
Kailang Yang272a5272007-05-14 11:00:38 +020013890static struct hda_verb alc861vd_dallas_verbs[] = {
13891 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13892 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13893 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13894 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13895
13896 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13897 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13898 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13899 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13900 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13901 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13902 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13903 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013904
Kailang Yang272a5272007-05-14 11:00:38 +020013905 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13906 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13907 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13908 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13909 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13910 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13911 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13912 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13913
13914 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13915 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13916 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13917 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13918 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13919 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13920 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13921 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13922
13923 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13924 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13925 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13926 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13927
13928 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013929 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020013930 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13931
13932 { } /* end */
13933};
13934
13935/* toggle speaker-output according to the hp-jack state */
13936static void alc861vd_dallas_automute(struct hda_codec *codec)
13937{
13938 unsigned int present;
13939
13940 present = snd_hda_codec_read(codec, 0x15, 0,
13941 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013942 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13943 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020013944}
13945
13946static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
13947{
13948 if ((res >> 26) == ALC880_HP_EVENT)
13949 alc861vd_dallas_automute(codec);
13950}
13951
Takashi Iwaicb53c622007-08-10 17:21:45 +020013952#ifdef CONFIG_SND_HDA_POWER_SAVE
13953#define alc861vd_loopbacks alc880_loopbacks
13954#endif
13955
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013956/* pcm configuration: identiacal with ALC880 */
13957#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
13958#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
13959#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
13960#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
13961
13962/*
13963 * configuration and preset
13964 */
13965static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
13966 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013967 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013968 [ALC861VD_3ST] = "3stack",
13969 [ALC861VD_3ST_DIG] = "3stack-digout",
13970 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020013971 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020013972 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013973 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013974 [ALC861VD_AUTO] = "auto",
13975};
13976
13977static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013978 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
13979 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010013980 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013981 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Alexander Holler2522d732008-07-17 23:36:15 +020013982 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
Mike Crash6963f842007-06-25 12:12:51 +020013983 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013984 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013985 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020013986 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020013987 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020013988 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010013989 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020013990 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013991 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
13992 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a892008-07-07 16:04:04 +020013993 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020013994 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013995 {}
13996};
13997
13998static struct alc_config_preset alc861vd_presets[] = {
13999 [ALC660VD_3ST] = {
14000 .mixers = { alc861vd_3st_mixer },
14001 .init_verbs = { alc861vd_volume_init_verbs,
14002 alc861vd_3stack_init_verbs },
14003 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14004 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014005 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14006 .channel_mode = alc861vd_3stack_2ch_modes,
14007 .input_mux = &alc861vd_capture_source,
14008 },
Mike Crash6963f842007-06-25 12:12:51 +020014009 [ALC660VD_3ST_DIG] = {
14010 .mixers = { alc861vd_3st_mixer },
14011 .init_verbs = { alc861vd_volume_init_verbs,
14012 alc861vd_3stack_init_verbs },
14013 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14014 .dac_nids = alc660vd_dac_nids,
14015 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014016 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14017 .channel_mode = alc861vd_3stack_2ch_modes,
14018 .input_mux = &alc861vd_capture_source,
14019 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014020 [ALC861VD_3ST] = {
14021 .mixers = { alc861vd_3st_mixer },
14022 .init_verbs = { alc861vd_volume_init_verbs,
14023 alc861vd_3stack_init_verbs },
14024 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14025 .dac_nids = alc861vd_dac_nids,
14026 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14027 .channel_mode = alc861vd_3stack_2ch_modes,
14028 .input_mux = &alc861vd_capture_source,
14029 },
14030 [ALC861VD_3ST_DIG] = {
14031 .mixers = { alc861vd_3st_mixer },
14032 .init_verbs = { alc861vd_volume_init_verbs,
14033 alc861vd_3stack_init_verbs },
14034 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14035 .dac_nids = alc861vd_dac_nids,
14036 .dig_out_nid = ALC861VD_DIGOUT_NID,
14037 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14038 .channel_mode = alc861vd_3stack_2ch_modes,
14039 .input_mux = &alc861vd_capture_source,
14040 },
14041 [ALC861VD_6ST_DIG] = {
14042 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14043 .init_verbs = { alc861vd_volume_init_verbs,
14044 alc861vd_6stack_init_verbs },
14045 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14046 .dac_nids = alc861vd_dac_nids,
14047 .dig_out_nid = ALC861VD_DIGOUT_NID,
14048 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14049 .channel_mode = alc861vd_6stack_modes,
14050 .input_mux = &alc861vd_capture_source,
14051 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014052 [ALC861VD_LENOVO] = {
14053 .mixers = { alc861vd_lenovo_mixer },
14054 .init_verbs = { alc861vd_volume_init_verbs,
14055 alc861vd_3stack_init_verbs,
14056 alc861vd_eapd_verbs,
14057 alc861vd_lenovo_unsol_verbs },
14058 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14059 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014060 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14061 .channel_mode = alc861vd_3stack_2ch_modes,
14062 .input_mux = &alc861vd_capture_source,
14063 .unsol_event = alc861vd_lenovo_unsol_event,
14064 .init_hook = alc861vd_lenovo_automute,
14065 },
Kailang Yang272a5272007-05-14 11:00:38 +020014066 [ALC861VD_DALLAS] = {
14067 .mixers = { alc861vd_dallas_mixer },
14068 .init_verbs = { alc861vd_dallas_verbs },
14069 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14070 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014071 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14072 .channel_mode = alc861vd_3stack_2ch_modes,
14073 .input_mux = &alc861vd_dallas_capture_source,
14074 .unsol_event = alc861vd_dallas_unsol_event,
14075 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014076 },
14077 [ALC861VD_HP] = {
14078 .mixers = { alc861vd_hp_mixer },
14079 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14080 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14081 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014082 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014083 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14084 .channel_mode = alc861vd_3stack_2ch_modes,
14085 .input_mux = &alc861vd_hp_capture_source,
14086 .unsol_event = alc861vd_dallas_unsol_event,
14087 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014088 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014089};
14090
14091/*
14092 * BIOS auto configuration
14093 */
14094static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14095 hda_nid_t nid, int pin_type, int dac_idx)
14096{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014097 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014098}
14099
14100static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14101{
14102 struct alc_spec *spec = codec->spec;
14103 int i;
14104
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014105 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014106 for (i = 0; i <= HDA_SIDE; i++) {
14107 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014108 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014109 if (nid)
14110 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014111 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014112 }
14113}
14114
14115
14116static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14117{
14118 struct alc_spec *spec = codec->spec;
14119 hda_nid_t pin;
14120
14121 pin = spec->autocfg.hp_pins[0];
14122 if (pin) /* connect to front and use dac 0 */
14123 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014124 pin = spec->autocfg.speaker_pins[0];
14125 if (pin)
14126 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014127}
14128
14129#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14130#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14131
14132static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14133{
14134 struct alc_spec *spec = codec->spec;
14135 int i;
14136
14137 for (i = 0; i < AUTO_PIN_LAST; i++) {
14138 hda_nid_t nid = spec->autocfg.input_pins[i];
14139 if (alc861vd_is_input_pin(nid)) {
14140 snd_hda_codec_write(codec, nid, 0,
14141 AC_VERB_SET_PIN_WIDGET_CONTROL,
14142 i <= AUTO_PIN_FRONT_MIC ?
14143 PIN_VREF80 : PIN_IN);
14144 if (nid != ALC861VD_PIN_CD_NID)
14145 snd_hda_codec_write(codec, nid, 0,
14146 AC_VERB_SET_AMP_GAIN_MUTE,
14147 AMP_OUT_MUTE);
14148 }
14149 }
14150}
14151
Takashi Iwaif511b012008-08-15 16:46:42 +020014152#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14153
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014154#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14155#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14156
14157/* add playback controls from the parsed DAC table */
14158/* Based on ALC880 version. But ALC861VD has separate,
14159 * different NIDs for mute/unmute switch and volume control */
14160static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14161 const struct auto_pin_cfg *cfg)
14162{
14163 char name[32];
14164 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14165 hda_nid_t nid_v, nid_s;
14166 int i, err;
14167
14168 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014169 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014170 continue;
14171 nid_v = alc861vd_idx_to_mixer_vol(
14172 alc880_dac_to_idx(
14173 spec->multiout.dac_nids[i]));
14174 nid_s = alc861vd_idx_to_mixer_switch(
14175 alc880_dac_to_idx(
14176 spec->multiout.dac_nids[i]));
14177
14178 if (i == 2) {
14179 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014180 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14181 "Center Playback Volume",
14182 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14183 HDA_OUTPUT));
14184 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014185 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014186 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14187 "LFE Playback Volume",
14188 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14189 HDA_OUTPUT));
14190 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014191 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014192 err = add_control(spec, ALC_CTL_BIND_MUTE,
14193 "Center Playback Switch",
14194 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14195 HDA_INPUT));
14196 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014197 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014198 err = add_control(spec, ALC_CTL_BIND_MUTE,
14199 "LFE Playback Switch",
14200 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14201 HDA_INPUT));
14202 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014203 return err;
14204 } else {
14205 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014206 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14207 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14208 HDA_OUTPUT));
14209 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014210 return err;
14211 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014212 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014213 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014214 HDA_INPUT));
14215 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014216 return err;
14217 }
14218 }
14219 return 0;
14220}
14221
14222/* add playback controls for speaker and HP outputs */
14223/* Based on ALC880 version. But ALC861VD has separate,
14224 * different NIDs for mute/unmute switch and volume control */
14225static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14226 hda_nid_t pin, const char *pfx)
14227{
14228 hda_nid_t nid_v, nid_s;
14229 int err;
14230 char name[32];
14231
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014232 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014233 return 0;
14234
14235 if (alc880_is_fixed_pin(pin)) {
14236 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14237 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014238 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014239 spec->multiout.hp_nid = nid_v;
14240 else
14241 spec->multiout.extra_out_nid[0] = nid_v;
14242 /* control HP volume/switch on the output mixer amp */
14243 nid_v = alc861vd_idx_to_mixer_vol(
14244 alc880_fixed_pin_idx(pin));
14245 nid_s = alc861vd_idx_to_mixer_switch(
14246 alc880_fixed_pin_idx(pin));
14247
14248 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014249 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14250 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14251 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014252 return err;
14253 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014254 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14255 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14256 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014257 return err;
14258 } else if (alc880_is_multi_pin(pin)) {
14259 /* set manual connection */
14260 /* we have only a switch on HP-out PIN */
14261 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014262 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14263 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14264 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014265 return err;
14266 }
14267 return 0;
14268}
14269
14270/* parse the BIOS configuration and set up the alc_spec
14271 * return 1 if successful, 0 if the proper config is not found,
14272 * or a negative error code
14273 * Based on ALC880 version - had to change it to override
14274 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14275static int alc861vd_parse_auto_config(struct hda_codec *codec)
14276{
14277 struct alc_spec *spec = codec->spec;
14278 int err;
14279 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14280
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014281 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14282 alc861vd_ignore);
14283 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014284 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014285 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014286 return 0; /* can't find valid BIOS pin config */
14287
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014288 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14289 if (err < 0)
14290 return err;
14291 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14292 if (err < 0)
14293 return err;
14294 err = alc861vd_auto_create_extra_out(spec,
14295 spec->autocfg.speaker_pins[0],
14296 "Speaker");
14297 if (err < 0)
14298 return err;
14299 err = alc861vd_auto_create_extra_out(spec,
14300 spec->autocfg.hp_pins[0],
14301 "Headphone");
14302 if (err < 0)
14303 return err;
14304 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14305 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014306 return err;
14307
14308 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14309
14310 if (spec->autocfg.dig_out_pin)
14311 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14312
14313 if (spec->kctl_alloc)
14314 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
14315
14316 spec->init_verbs[spec->num_init_verbs++]
14317 = alc861vd_volume_init_verbs;
14318
14319 spec->num_mux_defs = 1;
14320 spec->input_mux = &spec->private_imux;
14321
Takashi Iwai776e1842007-08-29 15:07:11 +020014322 err = alc_auto_add_mic_boost(codec);
14323 if (err < 0)
14324 return err;
14325
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014326 return 1;
14327}
14328
14329/* additional initialization for auto-configuration model */
14330static void alc861vd_auto_init(struct hda_codec *codec)
14331{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014332 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014333 alc861vd_auto_init_multi_out(codec);
14334 alc861vd_auto_init_hp_out(codec);
14335 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014336 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014337 if (spec->unsol_event)
14338 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014339}
14340
14341static int patch_alc861vd(struct hda_codec *codec)
14342{
14343 struct alc_spec *spec;
14344 int err, board_config;
14345
14346 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14347 if (spec == NULL)
14348 return -ENOMEM;
14349
14350 codec->spec = spec;
14351
14352 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14353 alc861vd_models,
14354 alc861vd_cfg_tbl);
14355
14356 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14357 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14358 "ALC861VD, trying auto-probe from BIOS...\n");
14359 board_config = ALC861VD_AUTO;
14360 }
14361
14362 if (board_config == ALC861VD_AUTO) {
14363 /* automatic parse from the BIOS config */
14364 err = alc861vd_parse_auto_config(codec);
14365 if (err < 0) {
14366 alc_free(codec);
14367 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014368 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014369 printk(KERN_INFO
14370 "hda_codec: Cannot set up configuration "
14371 "from BIOS. Using base mode...\n");
14372 board_config = ALC861VD_3ST;
14373 }
14374 }
14375
14376 if (board_config != ALC861VD_AUTO)
14377 setup_preset(spec, &alc861vd_presets[board_config]);
14378
Kailang Yang2f893282008-05-27 12:14:47 +020014379 if (codec->vendor_id == 0x10ec0660) {
14380 spec->stream_name_analog = "ALC660-VD Analog";
14381 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014382 /* always turn on EAPD */
14383 spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs;
Kailang Yang2f893282008-05-27 12:14:47 +020014384 } else {
14385 spec->stream_name_analog = "ALC861VD Analog";
14386 spec->stream_name_digital = "ALC861VD Digital";
14387 }
14388
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014389 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
14390 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
14391
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014392 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
14393 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
14394
14395 spec->adc_nids = alc861vd_adc_nids;
14396 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010014397 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014398
14399 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
14400 spec->num_mixers++;
14401
Takashi Iwai2134ea42008-01-10 16:53:55 +010014402 spec->vmaster_nid = 0x02;
14403
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014404 codec->patch_ops = alc_patch_ops;
14405
14406 if (board_config == ALC861VD_AUTO)
14407 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014408#ifdef CONFIG_SND_HDA_POWER_SAVE
14409 if (!spec->loopback.amplist)
14410 spec->loopback.amplist = alc861vd_loopbacks;
14411#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014412
14413 return 0;
14414}
14415
14416/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014417 * ALC662 support
14418 *
14419 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
14420 * configuration. Each pin widget can choose any input DACs and a mixer.
14421 * Each ADC is connected from a mixer of all inputs. This makes possible
14422 * 6-channel independent captures.
14423 *
14424 * In addition, an independent DAC for the multi-playback (not used in this
14425 * driver yet).
14426 */
14427#define ALC662_DIGOUT_NID 0x06
14428#define ALC662_DIGIN_NID 0x0a
14429
14430static hda_nid_t alc662_dac_nids[4] = {
14431 /* front, rear, clfe, rear_surr */
14432 0x02, 0x03, 0x04
14433};
14434
14435static hda_nid_t alc662_adc_nids[1] = {
14436 /* ADC1-2 */
14437 0x09,
14438};
Takashi Iwaie1406342008-02-11 18:32:32 +010014439
Kailang Yang77a261b2008-02-19 11:38:05 +010014440static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010014441
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014442/* input MUX */
14443/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014444static struct hda_input_mux alc662_capture_source = {
14445 .num_items = 4,
14446 .items = {
14447 { "Mic", 0x0 },
14448 { "Front Mic", 0x1 },
14449 { "Line", 0x2 },
14450 { "CD", 0x4 },
14451 },
14452};
14453
14454static struct hda_input_mux alc662_lenovo_101e_capture_source = {
14455 .num_items = 2,
14456 .items = {
14457 { "Mic", 0x1 },
14458 { "Line", 0x2 },
14459 },
14460};
Kailang Yang291702f2007-10-16 14:28:03 +020014461
14462static struct hda_input_mux alc662_eeepc_capture_source = {
14463 .num_items = 2,
14464 .items = {
14465 { "i-Mic", 0x1 },
14466 { "e-Mic", 0x0 },
14467 },
14468};
14469
Kailang Yang6dda9f42008-05-27 12:05:31 +020014470static struct hda_input_mux alc663_capture_source = {
14471 .num_items = 3,
14472 .items = {
14473 { "Mic", 0x0 },
14474 { "Front Mic", 0x1 },
14475 { "Line", 0x2 },
14476 },
14477};
14478
14479static struct hda_input_mux alc663_m51va_capture_source = {
14480 .num_items = 2,
14481 .items = {
14482 { "Ext-Mic", 0x0 },
14483 { "D-Mic", 0x9 },
14484 },
14485};
14486
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014487#define alc662_mux_enum_info alc_mux_enum_info
14488#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010014489#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014490
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014491/*
14492 * 2ch mode
14493 */
14494static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
14495 { 2, NULL }
14496};
14497
14498/*
14499 * 2ch mode
14500 */
14501static struct hda_verb alc662_3ST_ch2_init[] = {
14502 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
14503 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14504 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
14505 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14506 { } /* end */
14507};
14508
14509/*
14510 * 6ch mode
14511 */
14512static struct hda_verb alc662_3ST_ch6_init[] = {
14513 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14514 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14515 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
14516 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14517 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14518 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
14519 { } /* end */
14520};
14521
14522static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
14523 { 2, alc662_3ST_ch2_init },
14524 { 6, alc662_3ST_ch6_init },
14525};
14526
14527/*
14528 * 2ch mode
14529 */
14530static struct hda_verb alc662_sixstack_ch6_init[] = {
14531 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14532 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14533 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14534 { } /* end */
14535};
14536
14537/*
14538 * 6ch mode
14539 */
14540static struct hda_verb alc662_sixstack_ch8_init[] = {
14541 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14542 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14543 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14544 { } /* end */
14545};
14546
14547static struct hda_channel_mode alc662_5stack_modes[2] = {
14548 { 2, alc662_sixstack_ch6_init },
14549 { 6, alc662_sixstack_ch8_init },
14550};
14551
14552/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14553 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14554 */
14555
14556static struct snd_kcontrol_new alc662_base_mixer[] = {
14557 /* output mixer control */
14558 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014559 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014560 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014561 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014562 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14563 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014564 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14565 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014566 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14567
14568 /*Input mixer control */
14569 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
14570 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
14571 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
14572 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
14573 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
14574 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
14575 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
14576 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014577 { } /* end */
14578};
14579
14580static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
14581 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014582 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014583 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14584 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14585 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14586 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14587 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14588 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14589 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14590 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14591 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14592 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14593 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014594 { } /* end */
14595};
14596
14597static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
14598 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014599 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014600 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014601 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014602 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14603 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014604 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14605 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014606 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14607 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14608 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14609 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14610 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14611 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14612 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14613 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14614 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14615 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14616 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014617 { } /* end */
14618};
14619
14620static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
14621 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14622 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014623 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14624 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014625 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14626 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14627 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14628 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14629 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014630 { } /* end */
14631};
14632
Kailang Yang291702f2007-10-16 14:28:03 +020014633static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010014634 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014635
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010014636 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14637 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014638
14639 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
14640 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14641 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14642
14643 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
14644 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14645 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14646 { } /* end */
14647};
14648
Kailang Yang8c427222008-01-10 13:03:59 +010014649static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010014650 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14651 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014652 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14653 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
14654 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14655 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
14656 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
14657 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014658 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014659 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
14660 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14661 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14662 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14663 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14664 { } /* end */
14665};
14666
Kailang Yangf1d4e282008-08-26 14:03:29 +020014667static struct hda_bind_ctls alc663_asus_bind_master_vol = {
14668 .ops = &snd_hda_bind_vol,
14669 .values = {
14670 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14671 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
14672 0
14673 },
14674};
14675
14676static struct hda_bind_ctls alc663_asus_one_bind_switch = {
14677 .ops = &snd_hda_bind_sw,
14678 .values = {
14679 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14680 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14681 0
14682 },
14683};
14684
Kailang Yang6dda9f42008-05-27 12:05:31 +020014685static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014686 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14687 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
14688 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14689 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14690 { } /* end */
14691};
14692
14693static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
14694 .ops = &snd_hda_bind_sw,
14695 .values = {
14696 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14697 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14698 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14699 0
14700 },
14701};
14702
14703static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
14704 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14705 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
14706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14707 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14708 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14709 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14710
14711 { } /* end */
14712};
14713
14714static struct hda_bind_ctls alc663_asus_four_bind_switch = {
14715 .ops = &snd_hda_bind_sw,
14716 .values = {
14717 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14718 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14719 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
14720 0
14721 },
14722};
14723
14724static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
14725 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14726 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
14727 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14728 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14729 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14730 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14731 { } /* end */
14732};
14733
14734static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020014735 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14736 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014737 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14738 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14739 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14740 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14741 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14742 { } /* end */
14743};
14744
14745static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
14746 .ops = &snd_hda_bind_vol,
14747 .values = {
14748 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14749 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
14750 0
14751 },
14752};
14753
14754static struct hda_bind_ctls alc663_asus_two_bind_switch = {
14755 .ops = &snd_hda_bind_sw,
14756 .values = {
14757 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14758 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
14759 0
14760 },
14761};
14762
14763static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
14764 HDA_BIND_VOL("Master Playback Volume",
14765 &alc663_asus_two_bind_master_vol),
14766 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14767 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014768 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14769 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14770 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014771 { } /* end */
14772};
14773
14774static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
14775 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14776 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14777 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14778 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14779 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14780 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014781 { } /* end */
14782};
14783
14784static struct snd_kcontrol_new alc663_g71v_mixer[] = {
14785 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14786 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14787 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14788 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14789 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14790
14791 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14792 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14793 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14794 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14795 { } /* end */
14796};
14797
14798static struct snd_kcontrol_new alc663_g50v_mixer[] = {
14799 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14800 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14801 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14802
14803 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14804 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14805 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14806 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14807 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14808 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14809 { } /* end */
14810};
14811
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014812static struct snd_kcontrol_new alc662_chmode_mixer[] = {
14813 {
14814 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14815 .name = "Channel Mode",
14816 .info = alc_ch_mode_info,
14817 .get = alc_ch_mode_get,
14818 .put = alc_ch_mode_put,
14819 },
14820 { } /* end */
14821};
14822
14823static struct hda_verb alc662_init_verbs[] = {
14824 /* ADC: mute amp left and right */
14825 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14826 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14827 /* Front mixer: unmute input/output amp left and right (volume = 0) */
14828
Takashi Iwaicb53c622007-08-10 17:21:45 +020014829 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14830 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14831 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14832 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14833 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014834
Kailang Yangb60dd392007-09-20 12:50:29 +020014835 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14836 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14837 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14838 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14839 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14840 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014841
14842 /* Front Pin: output 0 (0x0c) */
14843 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14844 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14845
14846 /* Rear Pin: output 1 (0x0d) */
14847 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14848 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14849
14850 /* CLFE Pin: output 2 (0x0e) */
14851 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14852 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14853
14854 /* Mic (rear) pin: input vref at 80% */
14855 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14856 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14857 /* Front Mic pin: input vref at 80% */
14858 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14859 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14860 /* Line In pin: input */
14861 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14862 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14863 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14864 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14865 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14866 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14867 /* CD pin widget for input */
14868 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14869
14870 /* FIXME: use matrix-type input source selection */
14871 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14872 /* Input mixer */
14873 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14874 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14875 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14876 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020014877
14878 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14879 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14880 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14881 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014882
14883 /* always trun on EAPD */
14884 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14885 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14886
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014887 { }
14888};
14889
14890static struct hda_verb alc662_sue_init_verbs[] = {
14891 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14892 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020014893 {}
14894};
14895
14896static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
14897 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14898 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14899 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014900};
14901
Kailang Yang8c427222008-01-10 13:03:59 +010014902/* Set Unsolicited Event*/
14903static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
14904 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14905 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14906 {}
14907};
14908
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014909/*
14910 * generic initialization of ADC, input mixers and output mixers
14911 */
14912static struct hda_verb alc662_auto_init_verbs[] = {
14913 /*
14914 * Unmute ADC and set the default input to mic-in
14915 */
14916 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14917 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14918
14919 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
14920 * mixer widget
14921 * Note: PASD motherboards uses the Line In 2 as the input for front
14922 * panel mic (mic 2)
14923 */
14924 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014925 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14926 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14927 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14928 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14929 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014930
14931 /*
14932 * Set up output mixers (0x0c - 0x0f)
14933 */
14934 /* set vol=0 to output mixers */
14935 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14936 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14937 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14938
14939 /* set up input amps for analog loopback */
14940 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020014941 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14942 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14943 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14944 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14945 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14946 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014947
14948
14949 /* FIXME: use matrix-type input source selection */
14950 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14951 /* Input mixer */
14952 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020014953 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014954 { }
14955};
14956
Takashi Iwai24fb9172008-09-02 14:48:20 +020014957/* additional verbs for ALC663 */
14958static struct hda_verb alc663_auto_init_verbs[] = {
14959 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14960 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14961 { }
14962};
14963
Kailang Yang6dda9f42008-05-27 12:05:31 +020014964static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014965 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14966 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014967 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14968 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020014969 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14970 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14971 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014972 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14973 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14974 {}
14975};
14976
Kailang Yangf1d4e282008-08-26 14:03:29 +020014977static struct hda_verb alc663_21jd_amic_init_verbs[] = {
14978 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14979 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14980 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14981 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14982 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14983 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14984 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14985 {}
14986};
14987
14988static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
14989 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14990 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14991 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14992 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14993 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14994 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14995 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14996 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14997 {}
14998};
14999
15000static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15001 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15002 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15003 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15004 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15005 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15006 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15007 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15008 {}
15009};
15010
15011static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15012 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15013 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15014 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15015 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15016 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15017 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15018 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15019 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15020 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15021 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15022 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15023 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15024 {}
15025};
15026
15027static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15028 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15029 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15030 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15031 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15032 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15033 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15034 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15036 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15037 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15038 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15039 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15040 {}
15041};
15042
Kailang Yang6dda9f42008-05-27 12:05:31 +020015043static struct hda_verb alc663_g71v_init_verbs[] = {
15044 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15045 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15046 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15047
15048 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15049 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15050 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15051
15052 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15053 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15054 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15055 {}
15056};
15057
15058static struct hda_verb alc663_g50v_init_verbs[] = {
15059 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15060 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15061 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15062
15063 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15064 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15065 {}
15066};
15067
Kailang Yangf1d4e282008-08-26 14:03:29 +020015068static struct hda_verb alc662_ecs_init_verbs[] = {
15069 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15070 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15071 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15072 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15073 {}
15074};
15075
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015076/* capture mixer elements */
15077static struct snd_kcontrol_new alc662_capture_mixer[] = {
15078 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15079 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15080 {
15081 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15082 /* The multiple "Capture Source" controls confuse alsamixer
15083 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015084 */
15085 /* .name = "Capture Source", */
15086 .name = "Input Source",
15087 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010015088 .info = alc662_mux_enum_info,
15089 .get = alc662_mux_enum_get,
15090 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015091 },
15092 { } /* end */
15093};
15094
Kailang Yangf1d4e282008-08-26 14:03:29 +020015095static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15096 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15097 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15098 { } /* end */
15099};
15100
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015101static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15102{
15103 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015104 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015105
15106 present = snd_hda_codec_read(codec, 0x14, 0,
15107 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015108 bits = present ? HDA_AMP_MUTE : 0;
15109 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15110 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015111}
15112
15113static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15114{
15115 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015116 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015117
15118 present = snd_hda_codec_read(codec, 0x1b, 0,
15119 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015120 bits = present ? HDA_AMP_MUTE : 0;
15121 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15122 HDA_AMP_MUTE, bits);
15123 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15124 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015125}
15126
15127static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15128 unsigned int res)
15129{
15130 if ((res >> 26) == ALC880_HP_EVENT)
15131 alc662_lenovo_101e_all_automute(codec);
15132 if ((res >> 26) == ALC880_FRONT_EVENT)
15133 alc662_lenovo_101e_ispeaker_automute(codec);
15134}
15135
Kailang Yang291702f2007-10-16 14:28:03 +020015136static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15137{
15138 unsigned int present;
15139
15140 present = snd_hda_codec_read(codec, 0x18, 0,
15141 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15142 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15143 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15144 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15145 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15146 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15147 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15148 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15149 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15150}
15151
15152/* unsolicited event for HP jack sensing */
15153static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15154 unsigned int res)
15155{
15156 if ((res >> 26) == ALC880_HP_EVENT)
15157 alc262_hippo1_automute( codec );
15158
15159 if ((res >> 26) == ALC880_MIC_EVENT)
15160 alc662_eeepc_mic_automute(codec);
15161}
15162
15163static void alc662_eeepc_inithook(struct hda_codec *codec)
15164{
15165 alc262_hippo1_automute( codec );
15166 alc662_eeepc_mic_automute(codec);
15167}
15168
Kailang Yang8c427222008-01-10 13:03:59 +010015169static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15170{
15171 unsigned int mute;
15172 unsigned int present;
15173
15174 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15175 present = snd_hda_codec_read(codec, 0x14, 0,
15176 AC_VERB_GET_PIN_SENSE, 0);
15177 present = (present & 0x80000000) != 0;
15178 if (present) {
15179 /* mute internal speaker */
15180 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015181 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015182 } else {
15183 /* unmute internal speaker if necessary */
15184 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15185 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015186 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015187 }
15188}
15189
15190/* unsolicited event for HP jack sensing */
15191static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15192 unsigned int res)
15193{
15194 if ((res >> 26) == ALC880_HP_EVENT)
15195 alc662_eeepc_ep20_automute(codec);
15196}
15197
15198static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15199{
15200 alc662_eeepc_ep20_automute(codec);
15201}
15202
Kailang Yang6dda9f42008-05-27 12:05:31 +020015203static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15204{
15205 unsigned int present;
15206 unsigned char bits;
15207
15208 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015209 AC_VERB_GET_PIN_SENSE, 0)
15210 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015211 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015212 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15213 AMP_IN_MUTE(0), bits);
15214 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15215 AMP_IN_MUTE(0), bits);
15216}
15217
15218static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15219{
15220 unsigned int present;
15221 unsigned char bits;
15222
15223 present = snd_hda_codec_read(codec, 0x21, 0,
15224 AC_VERB_GET_PIN_SENSE, 0)
15225 & AC_PINSENSE_PRESENCE;
15226 bits = present ? HDA_AMP_MUTE : 0;
15227 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15228 AMP_IN_MUTE(0), bits);
15229 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15230 AMP_IN_MUTE(0), bits);
15231 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15232 AMP_IN_MUTE(0), bits);
15233 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15234 AMP_IN_MUTE(0), bits);
15235}
15236
15237static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15238{
15239 unsigned int present;
15240 unsigned char bits;
15241
15242 present = snd_hda_codec_read(codec, 0x15, 0,
15243 AC_VERB_GET_PIN_SENSE, 0)
15244 & AC_PINSENSE_PRESENCE;
15245 bits = present ? HDA_AMP_MUTE : 0;
15246 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15247 AMP_IN_MUTE(0), bits);
15248 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15249 AMP_IN_MUTE(0), bits);
15250 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15251 AMP_IN_MUTE(0), bits);
15252 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15253 AMP_IN_MUTE(0), bits);
15254}
15255
15256static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15257{
15258 unsigned int present;
15259 unsigned char bits;
15260
15261 present = snd_hda_codec_read(codec, 0x1b, 0,
15262 AC_VERB_GET_PIN_SENSE, 0)
15263 & AC_PINSENSE_PRESENCE;
15264 bits = present ? 0 : PIN_OUT;
15265 snd_hda_codec_write(codec, 0x14, 0,
15266 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15267}
15268
15269static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15270{
15271 unsigned int present1, present2;
15272
15273 present1 = snd_hda_codec_read(codec, 0x21, 0,
15274 AC_VERB_GET_PIN_SENSE, 0)
15275 & AC_PINSENSE_PRESENCE;
15276 present2 = snd_hda_codec_read(codec, 0x15, 0,
15277 AC_VERB_GET_PIN_SENSE, 0)
15278 & AC_PINSENSE_PRESENCE;
15279
15280 if (present1 || present2) {
15281 snd_hda_codec_write_cache(codec, 0x14, 0,
15282 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15283 } else {
15284 snd_hda_codec_write_cache(codec, 0x14, 0,
15285 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15286 }
15287}
15288
15289static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15290{
15291 unsigned int present1, present2;
15292
15293 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15294 AC_VERB_GET_PIN_SENSE, 0)
15295 & AC_PINSENSE_PRESENCE;
15296 present2 = snd_hda_codec_read(codec, 0x15, 0,
15297 AC_VERB_GET_PIN_SENSE, 0)
15298 & AC_PINSENSE_PRESENCE;
15299
15300 if (present1 || present2) {
15301 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15302 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15303 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15304 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15305 } else {
15306 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15307 AMP_IN_MUTE(0), 0);
15308 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15309 AMP_IN_MUTE(0), 0);
15310 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015311}
15312
15313static void alc663_m51va_mic_automute(struct hda_codec *codec)
15314{
15315 unsigned int present;
15316
15317 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015318 AC_VERB_GET_PIN_SENSE, 0)
15319 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015320 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015321 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015322 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015323 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015324 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015325 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015326 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015327 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015328}
15329
15330static void alc663_m51va_unsol_event(struct hda_codec *codec,
15331 unsigned int res)
15332{
15333 switch (res >> 26) {
15334 case ALC880_HP_EVENT:
15335 alc663_m51va_speaker_automute(codec);
15336 break;
15337 case ALC880_MIC_EVENT:
15338 alc663_m51va_mic_automute(codec);
15339 break;
15340 }
15341}
15342
15343static void alc663_m51va_inithook(struct hda_codec *codec)
15344{
15345 alc663_m51va_speaker_automute(codec);
15346 alc663_m51va_mic_automute(codec);
15347}
15348
Kailang Yangf1d4e282008-08-26 14:03:29 +020015349/* ***************** Mode1 ******************************/
15350static void alc663_mode1_unsol_event(struct hda_codec *codec,
15351 unsigned int res)
15352{
15353 switch (res >> 26) {
15354 case ALC880_HP_EVENT:
15355 alc663_m51va_speaker_automute(codec);
15356 break;
15357 case ALC880_MIC_EVENT:
15358 alc662_eeepc_mic_automute(codec);
15359 break;
15360 }
15361}
15362
15363static void alc663_mode1_inithook(struct hda_codec *codec)
15364{
15365 alc663_m51va_speaker_automute(codec);
15366 alc662_eeepc_mic_automute(codec);
15367}
15368/* ***************** Mode2 ******************************/
15369static void alc662_mode2_unsol_event(struct hda_codec *codec,
15370 unsigned int res)
15371{
15372 switch (res >> 26) {
15373 case ALC880_HP_EVENT:
15374 alc662_f5z_speaker_automute(codec);
15375 break;
15376 case ALC880_MIC_EVENT:
15377 alc662_eeepc_mic_automute(codec);
15378 break;
15379 }
15380}
15381
15382static void alc662_mode2_inithook(struct hda_codec *codec)
15383{
15384 alc662_f5z_speaker_automute(codec);
15385 alc662_eeepc_mic_automute(codec);
15386}
15387/* ***************** Mode3 ******************************/
15388static void alc663_mode3_unsol_event(struct hda_codec *codec,
15389 unsigned int res)
15390{
15391 switch (res >> 26) {
15392 case ALC880_HP_EVENT:
15393 alc663_two_hp_m1_speaker_automute(codec);
15394 break;
15395 case ALC880_MIC_EVENT:
15396 alc662_eeepc_mic_automute(codec);
15397 break;
15398 }
15399}
15400
15401static void alc663_mode3_inithook(struct hda_codec *codec)
15402{
15403 alc663_two_hp_m1_speaker_automute(codec);
15404 alc662_eeepc_mic_automute(codec);
15405}
15406/* ***************** Mode4 ******************************/
15407static void alc663_mode4_unsol_event(struct hda_codec *codec,
15408 unsigned int res)
15409{
15410 switch (res >> 26) {
15411 case ALC880_HP_EVENT:
15412 alc663_21jd_two_speaker_automute(codec);
15413 break;
15414 case ALC880_MIC_EVENT:
15415 alc662_eeepc_mic_automute(codec);
15416 break;
15417 }
15418}
15419
15420static void alc663_mode4_inithook(struct hda_codec *codec)
15421{
15422 alc663_21jd_two_speaker_automute(codec);
15423 alc662_eeepc_mic_automute(codec);
15424}
15425/* ***************** Mode5 ******************************/
15426static void alc663_mode5_unsol_event(struct hda_codec *codec,
15427 unsigned int res)
15428{
15429 switch (res >> 26) {
15430 case ALC880_HP_EVENT:
15431 alc663_15jd_two_speaker_automute(codec);
15432 break;
15433 case ALC880_MIC_EVENT:
15434 alc662_eeepc_mic_automute(codec);
15435 break;
15436 }
15437}
15438
15439static void alc663_mode5_inithook(struct hda_codec *codec)
15440{
15441 alc663_15jd_two_speaker_automute(codec);
15442 alc662_eeepc_mic_automute(codec);
15443}
15444/* ***************** Mode6 ******************************/
15445static void alc663_mode6_unsol_event(struct hda_codec *codec,
15446 unsigned int res)
15447{
15448 switch (res >> 26) {
15449 case ALC880_HP_EVENT:
15450 alc663_two_hp_m2_speaker_automute(codec);
15451 break;
15452 case ALC880_MIC_EVENT:
15453 alc662_eeepc_mic_automute(codec);
15454 break;
15455 }
15456}
15457
15458static void alc663_mode6_inithook(struct hda_codec *codec)
15459{
15460 alc663_two_hp_m2_speaker_automute(codec);
15461 alc662_eeepc_mic_automute(codec);
15462}
15463
Kailang Yang6dda9f42008-05-27 12:05:31 +020015464static void alc663_g71v_hp_automute(struct hda_codec *codec)
15465{
15466 unsigned int present;
15467 unsigned char bits;
15468
15469 present = snd_hda_codec_read(codec, 0x21, 0,
15470 AC_VERB_GET_PIN_SENSE, 0)
15471 & AC_PINSENSE_PRESENCE;
15472 bits = present ? HDA_AMP_MUTE : 0;
15473 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15474 HDA_AMP_MUTE, bits);
15475 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15476 HDA_AMP_MUTE, bits);
15477}
15478
15479static void alc663_g71v_front_automute(struct hda_codec *codec)
15480{
15481 unsigned int present;
15482 unsigned char bits;
15483
15484 present = snd_hda_codec_read(codec, 0x15, 0,
15485 AC_VERB_GET_PIN_SENSE, 0)
15486 & AC_PINSENSE_PRESENCE;
15487 bits = present ? HDA_AMP_MUTE : 0;
15488 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15489 HDA_AMP_MUTE, bits);
15490}
15491
15492static void alc663_g71v_unsol_event(struct hda_codec *codec,
15493 unsigned int res)
15494{
15495 switch (res >> 26) {
15496 case ALC880_HP_EVENT:
15497 alc663_g71v_hp_automute(codec);
15498 break;
15499 case ALC880_FRONT_EVENT:
15500 alc663_g71v_front_automute(codec);
15501 break;
15502 case ALC880_MIC_EVENT:
15503 alc662_eeepc_mic_automute(codec);
15504 break;
15505 }
15506}
15507
15508static void alc663_g71v_inithook(struct hda_codec *codec)
15509{
15510 alc663_g71v_front_automute(codec);
15511 alc663_g71v_hp_automute(codec);
15512 alc662_eeepc_mic_automute(codec);
15513}
15514
15515static void alc663_g50v_unsol_event(struct hda_codec *codec,
15516 unsigned int res)
15517{
15518 switch (res >> 26) {
15519 case ALC880_HP_EVENT:
15520 alc663_m51va_speaker_automute(codec);
15521 break;
15522 case ALC880_MIC_EVENT:
15523 alc662_eeepc_mic_automute(codec);
15524 break;
15525 }
15526}
15527
15528static void alc663_g50v_inithook(struct hda_codec *codec)
15529{
15530 alc663_m51va_speaker_automute(codec);
15531 alc662_eeepc_mic_automute(codec);
15532}
15533
Kailang Yangf1d4e282008-08-26 14:03:29 +020015534/* bind hp and internal speaker mute (with plug check) */
15535static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
15536 struct snd_ctl_elem_value *ucontrol)
15537{
15538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
15539 long *valp = ucontrol->value.integer.value;
15540 int change;
15541
15542 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
15543 HDA_AMP_MUTE,
15544 valp[0] ? 0 : HDA_AMP_MUTE);
15545 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
15546 HDA_AMP_MUTE,
15547 valp[1] ? 0 : HDA_AMP_MUTE);
15548 if (change)
15549 alc262_hippo1_automute(codec);
15550 return change;
15551}
15552
15553static struct snd_kcontrol_new alc662_ecs_mixer[] = {
15554 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15555 {
15556 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15557 .name = "Master Playback Switch",
15558 .info = snd_hda_mixer_amp_switch_info,
15559 .get = snd_hda_mixer_amp_switch_get,
15560 .put = alc662_ecs_master_sw_put,
15561 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15562 },
15563
15564 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
15565 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
15566 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
15567
15568 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15569 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15570 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15571 { } /* end */
15572};
15573
Takashi Iwaicb53c622007-08-10 17:21:45 +020015574#ifdef CONFIG_SND_HDA_POWER_SAVE
15575#define alc662_loopbacks alc880_loopbacks
15576#endif
15577
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015578
15579/* pcm configuration: identiacal with ALC880 */
15580#define alc662_pcm_analog_playback alc880_pcm_analog_playback
15581#define alc662_pcm_analog_capture alc880_pcm_analog_capture
15582#define alc662_pcm_digital_playback alc880_pcm_digital_playback
15583#define alc662_pcm_digital_capture alc880_pcm_digital_capture
15584
15585/*
15586 * configuration and preset
15587 */
15588static const char *alc662_models[ALC662_MODEL_LAST] = {
15589 [ALC662_3ST_2ch_DIG] = "3stack-dig",
15590 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
15591 [ALC662_3ST_6ch] = "3stack-6ch",
15592 [ALC662_5ST_DIG] = "6stack-dig",
15593 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020015594 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010015595 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015596 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020015597 [ALC663_ASUS_M51VA] = "m51va",
15598 [ALC663_ASUS_G71V] = "g71v",
15599 [ALC663_ASUS_H13] = "h13",
15600 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015601 [ALC663_ASUS_MODE1] = "asus-mode1",
15602 [ALC662_ASUS_MODE2] = "asus-mode2",
15603 [ALC663_ASUS_MODE3] = "asus-mode3",
15604 [ALC663_ASUS_MODE4] = "asus-mode4",
15605 [ALC663_ASUS_MODE5] = "asus-mode5",
15606 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015607 [ALC662_AUTO] = "auto",
15608};
15609
15610static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015611 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
15612 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010015613 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020015614 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010015615 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015616 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
15617 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
15618 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
15619 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
15620 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
15621 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
15622 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
15623 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
15624 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
15625 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
15626 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
15627 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
15628 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
15629 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
15630 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
15631 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
15632 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
15633 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
15634 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
15635 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
15636 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
15637 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
15638 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
15639 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
15640 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
15641 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
15642 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
15643 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
15644 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
15645 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
15646 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015647 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015648 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
15649 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015650 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
15651 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
15652 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015653 {}
15654};
15655
15656static struct alc_config_preset alc662_presets[] = {
15657 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015658 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015659 .init_verbs = { alc662_init_verbs },
15660 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15661 .dac_nids = alc662_dac_nids,
15662 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015663 .dig_in_nid = ALC662_DIGIN_NID,
15664 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15665 .channel_mode = alc662_3ST_2ch_modes,
15666 .input_mux = &alc662_capture_source,
15667 },
15668 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015669 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
15670 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015671 .init_verbs = { alc662_init_verbs },
15672 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15673 .dac_nids = alc662_dac_nids,
15674 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015675 .dig_in_nid = ALC662_DIGIN_NID,
15676 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15677 .channel_mode = alc662_3ST_6ch_modes,
15678 .need_dac_fix = 1,
15679 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015680 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015681 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015682 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
15683 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015684 .init_verbs = { alc662_init_verbs },
15685 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15686 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015687 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15688 .channel_mode = alc662_3ST_6ch_modes,
15689 .need_dac_fix = 1,
15690 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015691 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015692 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015693 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
15694 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015695 .init_verbs = { alc662_init_verbs },
15696 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15697 .dac_nids = alc662_dac_nids,
15698 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015699 .dig_in_nid = ALC662_DIGIN_NID,
15700 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
15701 .channel_mode = alc662_5stack_modes,
15702 .input_mux = &alc662_capture_source,
15703 },
15704 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015705 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015706 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
15707 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15708 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015709 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15710 .channel_mode = alc662_3ST_2ch_modes,
15711 .input_mux = &alc662_lenovo_101e_capture_source,
15712 .unsol_event = alc662_lenovo_101e_unsol_event,
15713 .init_hook = alc662_lenovo_101e_all_automute,
15714 },
Kailang Yang291702f2007-10-16 14:28:03 +020015715 [ALC662_ASUS_EEEPC_P701] = {
15716 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
15717 .init_verbs = { alc662_init_verbs,
15718 alc662_eeepc_sue_init_verbs },
15719 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15720 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020015721 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15722 .channel_mode = alc662_3ST_2ch_modes,
15723 .input_mux = &alc662_eeepc_capture_source,
15724 .unsol_event = alc662_eeepc_unsol_event,
15725 .init_hook = alc662_eeepc_inithook,
15726 },
Kailang Yang8c427222008-01-10 13:03:59 +010015727 [ALC662_ASUS_EEEPC_EP20] = {
15728 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
15729 alc662_chmode_mixer },
15730 .init_verbs = { alc662_init_verbs,
15731 alc662_eeepc_ep20_sue_init_verbs },
15732 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15733 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010015734 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15735 .channel_mode = alc662_3ST_6ch_modes,
15736 .input_mux = &alc662_lenovo_101e_capture_source,
15737 .unsol_event = alc662_eeepc_ep20_unsol_event,
15738 .init_hook = alc662_eeepc_ep20_inithook,
15739 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015740 [ALC662_ECS] = {
15741 .mixers = { alc662_ecs_mixer, alc662_capture_mixer },
15742 .init_verbs = { alc662_init_verbs,
15743 alc662_ecs_init_verbs },
15744 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15745 .dac_nids = alc662_dac_nids,
15746 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15747 .channel_mode = alc662_3ST_2ch_modes,
15748 .input_mux = &alc662_eeepc_capture_source,
15749 .unsol_event = alc662_eeepc_unsol_event,
15750 .init_hook = alc662_eeepc_inithook,
15751 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015752 [ALC663_ASUS_M51VA] = {
15753 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
15754 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15755 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15756 .dac_nids = alc662_dac_nids,
15757 .dig_out_nid = ALC662_DIGOUT_NID,
15758 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15759 .channel_mode = alc662_3ST_2ch_modes,
15760 .input_mux = &alc663_m51va_capture_source,
15761 .unsol_event = alc663_m51va_unsol_event,
15762 .init_hook = alc663_m51va_inithook,
15763 },
15764 [ALC663_ASUS_G71V] = {
15765 .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
15766 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
15767 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15768 .dac_nids = alc662_dac_nids,
15769 .dig_out_nid = ALC662_DIGOUT_NID,
15770 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15771 .channel_mode = alc662_3ST_2ch_modes,
15772 .input_mux = &alc662_eeepc_capture_source,
15773 .unsol_event = alc663_g71v_unsol_event,
15774 .init_hook = alc663_g71v_inithook,
15775 },
15776 [ALC663_ASUS_H13] = {
15777 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
15778 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15779 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15780 .dac_nids = alc662_dac_nids,
15781 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15782 .channel_mode = alc662_3ST_2ch_modes,
15783 .input_mux = &alc663_m51va_capture_source,
15784 .unsol_event = alc663_m51va_unsol_event,
15785 .init_hook = alc663_m51va_inithook,
15786 },
15787 [ALC663_ASUS_G50V] = {
15788 .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
15789 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
15790 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15791 .dac_nids = alc662_dac_nids,
15792 .dig_out_nid = ALC662_DIGOUT_NID,
15793 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15794 .channel_mode = alc662_3ST_6ch_modes,
15795 .input_mux = &alc663_capture_source,
15796 .unsol_event = alc663_g50v_unsol_event,
15797 .init_hook = alc663_g50v_inithook,
15798 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015799 [ALC663_ASUS_MODE1] = {
15800 .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer },
15801 .init_verbs = { alc662_init_verbs,
15802 alc663_21jd_amic_init_verbs },
15803 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15804 .hp_nid = 0x03,
15805 .dac_nids = alc662_dac_nids,
15806 .dig_out_nid = ALC662_DIGOUT_NID,
15807 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15808 .channel_mode = alc662_3ST_2ch_modes,
15809 .input_mux = &alc662_eeepc_capture_source,
15810 .unsol_event = alc663_mode1_unsol_event,
15811 .init_hook = alc663_mode1_inithook,
15812 },
15813 [ALC662_ASUS_MODE2] = {
15814 .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer },
15815 .init_verbs = { alc662_init_verbs,
15816 alc662_1bjd_amic_init_verbs },
15817 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15818 .dac_nids = alc662_dac_nids,
15819 .dig_out_nid = ALC662_DIGOUT_NID,
15820 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15821 .channel_mode = alc662_3ST_2ch_modes,
15822 .input_mux = &alc662_eeepc_capture_source,
15823 .unsol_event = alc662_mode2_unsol_event,
15824 .init_hook = alc662_mode2_inithook,
15825 },
15826 [ALC663_ASUS_MODE3] = {
15827 .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer },
15828 .init_verbs = { alc662_init_verbs,
15829 alc663_two_hp_amic_m1_init_verbs },
15830 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15831 .hp_nid = 0x03,
15832 .dac_nids = alc662_dac_nids,
15833 .dig_out_nid = ALC662_DIGOUT_NID,
15834 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15835 .channel_mode = alc662_3ST_2ch_modes,
15836 .input_mux = &alc662_eeepc_capture_source,
15837 .unsol_event = alc663_mode3_unsol_event,
15838 .init_hook = alc663_mode3_inithook,
15839 },
15840 [ALC663_ASUS_MODE4] = {
15841 .mixers = { alc663_asus_21jd_clfe_mixer,
15842 alc662_auto_capture_mixer},
15843 .init_verbs = { alc662_init_verbs,
15844 alc663_21jd_amic_init_verbs},
15845 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15846 .hp_nid = 0x03,
15847 .dac_nids = alc662_dac_nids,
15848 .dig_out_nid = ALC662_DIGOUT_NID,
15849 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15850 .channel_mode = alc662_3ST_2ch_modes,
15851 .input_mux = &alc662_eeepc_capture_source,
15852 .unsol_event = alc663_mode4_unsol_event,
15853 .init_hook = alc663_mode4_inithook,
15854 },
15855 [ALC663_ASUS_MODE5] = {
15856 .mixers = { alc663_asus_15jd_clfe_mixer,
15857 alc662_auto_capture_mixer },
15858 .init_verbs = { alc662_init_verbs,
15859 alc663_15jd_amic_init_verbs },
15860 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15861 .hp_nid = 0x03,
15862 .dac_nids = alc662_dac_nids,
15863 .dig_out_nid = ALC662_DIGOUT_NID,
15864 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15865 .channel_mode = alc662_3ST_2ch_modes,
15866 .input_mux = &alc662_eeepc_capture_source,
15867 .unsol_event = alc663_mode5_unsol_event,
15868 .init_hook = alc663_mode5_inithook,
15869 },
15870 [ALC663_ASUS_MODE6] = {
15871 .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer },
15872 .init_verbs = { alc662_init_verbs,
15873 alc663_two_hp_amic_m2_init_verbs },
15874 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15875 .hp_nid = 0x03,
15876 .dac_nids = alc662_dac_nids,
15877 .dig_out_nid = ALC662_DIGOUT_NID,
15878 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15879 .channel_mode = alc662_3ST_2ch_modes,
15880 .input_mux = &alc662_eeepc_capture_source,
15881 .unsol_event = alc663_mode6_unsol_event,
15882 .init_hook = alc663_mode6_inithook,
15883 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015884};
15885
15886
15887/*
15888 * BIOS auto configuration
15889 */
15890
15891/* add playback controls from the parsed DAC table */
15892static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
15893 const struct auto_pin_cfg *cfg)
15894{
15895 char name[32];
15896 static const char *chname[4] = {
15897 "Front", "Surround", NULL /*CLFE*/, "Side"
15898 };
15899 hda_nid_t nid;
15900 int i, err;
15901
15902 for (i = 0; i < cfg->line_outs; i++) {
15903 if (!spec->multiout.dac_nids[i])
15904 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020015905 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015906 if (i == 2) {
15907 /* Center/LFE */
15908 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15909 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015910 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
15911 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015912 if (err < 0)
15913 return err;
15914 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15915 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015916 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
15917 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015918 if (err < 0)
15919 return err;
15920 err = add_control(spec, ALC_CTL_BIND_MUTE,
15921 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015922 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
15923 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015924 if (err < 0)
15925 return err;
15926 err = add_control(spec, ALC_CTL_BIND_MUTE,
15927 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015928 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
15929 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015930 if (err < 0)
15931 return err;
15932 } else {
15933 sprintf(name, "%s Playback Volume", chname[i]);
15934 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015935 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
15936 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015937 if (err < 0)
15938 return err;
15939 sprintf(name, "%s Playback Switch", chname[i]);
15940 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015941 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
15942 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015943 if (err < 0)
15944 return err;
15945 }
15946 }
15947 return 0;
15948}
15949
15950/* add playback controls for speaker and HP outputs */
15951static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
15952 const char *pfx)
15953{
15954 hda_nid_t nid;
15955 int err;
15956 char name[32];
15957
15958 if (!pin)
15959 return 0;
15960
Takashi Iwai24fb9172008-09-02 14:48:20 +020015961 if (pin == 0x17) {
15962 /* ALC663 has a mono output pin on 0x17 */
15963 sprintf(name, "%s Playback Switch", pfx);
15964 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15965 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
15966 return err;
15967 }
15968
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015969 if (alc880_is_fixed_pin(pin)) {
15970 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15971 /* printk("DAC nid=%x\n",nid); */
15972 /* specify the DAC as the extra output */
15973 if (!spec->multiout.hp_nid)
15974 spec->multiout.hp_nid = nid;
15975 else
15976 spec->multiout.extra_out_nid[0] = nid;
15977 /* control HP volume/switch on the output mixer amp */
15978 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15979 sprintf(name, "%s Playback Volume", pfx);
15980 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15981 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
15982 if (err < 0)
15983 return err;
15984 sprintf(name, "%s Playback Switch", pfx);
15985 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15986 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
15987 if (err < 0)
15988 return err;
15989 } else if (alc880_is_multi_pin(pin)) {
15990 /* set manual connection */
15991 /* we have only a switch on HP-out PIN */
15992 sprintf(name, "%s Playback Switch", pfx);
15993 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15994 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15995 if (err < 0)
15996 return err;
15997 }
15998 return 0;
15999}
16000
16001/* create playback/capture controls for input pins */
16002static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
16003 const struct auto_pin_cfg *cfg)
16004{
16005 struct hda_input_mux *imux = &spec->private_imux;
16006 int i, err, idx;
16007
16008 for (i = 0; i < AUTO_PIN_LAST; i++) {
16009 if (alc880_is_input_pin(cfg->input_pins[i])) {
16010 idx = alc880_input_pin_idx(cfg->input_pins[i]);
16011 err = new_analog_input(spec, cfg->input_pins[i],
16012 auto_pin_cfg_labels[i],
16013 idx, 0x0b);
16014 if (err < 0)
16015 return err;
16016 imux->items[imux->num_items].label =
16017 auto_pin_cfg_labels[i];
16018 imux->items[imux->num_items].index =
16019 alc880_input_pin_idx(cfg->input_pins[i]);
16020 imux->num_items++;
16021 }
16022 }
16023 return 0;
16024}
16025
16026static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16027 hda_nid_t nid, int pin_type,
16028 int dac_idx)
16029{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016030 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016031 /* need the manual connection? */
16032 if (alc880_is_multi_pin(nid)) {
16033 struct alc_spec *spec = codec->spec;
16034 int idx = alc880_multi_pin_idx(nid);
16035 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16036 AC_VERB_SET_CONNECT_SEL,
16037 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16038 }
16039}
16040
16041static void alc662_auto_init_multi_out(struct hda_codec *codec)
16042{
16043 struct alc_spec *spec = codec->spec;
16044 int i;
16045
Kailang Yang8c427222008-01-10 13:03:59 +010016046 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016047 for (i = 0; i <= HDA_SIDE; i++) {
16048 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016049 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016050 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016051 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016052 i);
16053 }
16054}
16055
16056static void alc662_auto_init_hp_out(struct hda_codec *codec)
16057{
16058 struct alc_spec *spec = codec->spec;
16059 hda_nid_t pin;
16060
16061 pin = spec->autocfg.hp_pins[0];
16062 if (pin) /* connect to front */
16063 /* use dac 0 */
16064 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016065 pin = spec->autocfg.speaker_pins[0];
16066 if (pin)
16067 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016068}
16069
16070#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
16071#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16072
16073static void alc662_auto_init_analog_input(struct hda_codec *codec)
16074{
16075 struct alc_spec *spec = codec->spec;
16076 int i;
16077
16078 for (i = 0; i < AUTO_PIN_LAST; i++) {
16079 hda_nid_t nid = spec->autocfg.input_pins[i];
16080 if (alc662_is_input_pin(nid)) {
16081 snd_hda_codec_write(codec, nid, 0,
16082 AC_VERB_SET_PIN_WIDGET_CONTROL,
16083 (i <= AUTO_PIN_FRONT_MIC ?
16084 PIN_VREF80 : PIN_IN));
16085 if (nid != ALC662_PIN_CD_NID)
16086 snd_hda_codec_write(codec, nid, 0,
16087 AC_VERB_SET_AMP_GAIN_MUTE,
16088 AMP_OUT_MUTE);
16089 }
16090 }
16091}
16092
Takashi Iwaif511b012008-08-15 16:46:42 +020016093#define alc662_auto_init_input_src alc882_auto_init_input_src
16094
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016095static int alc662_parse_auto_config(struct hda_codec *codec)
16096{
16097 struct alc_spec *spec = codec->spec;
16098 int err;
16099 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16100
16101 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16102 alc662_ignore);
16103 if (err < 0)
16104 return err;
16105 if (!spec->autocfg.line_outs)
16106 return 0; /* can't find valid BIOS pin config */
16107
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016108 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16109 if (err < 0)
16110 return err;
16111 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16112 if (err < 0)
16113 return err;
16114 err = alc662_auto_create_extra_out(spec,
16115 spec->autocfg.speaker_pins[0],
16116 "Speaker");
16117 if (err < 0)
16118 return err;
16119 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
16120 "Headphone");
16121 if (err < 0)
16122 return err;
16123 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
16124 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016125 return err;
16126
16127 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16128
16129 if (spec->autocfg.dig_out_pin)
16130 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
16131
16132 if (spec->kctl_alloc)
16133 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
16134
16135 spec->num_mux_defs = 1;
16136 spec->input_mux = &spec->private_imux;
Kailang Yangea1fb292008-08-26 12:58:38 +020016137
Takashi Iwai8c872862007-06-19 12:11:16 +020016138 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Takashi Iwai24fb9172008-09-02 14:48:20 +020016139 if (codec->vendor_id == 0x10ec0663)
16140 spec->init_verbs[spec->num_init_verbs++] =
16141 alc663_auto_init_verbs;
Takashi Iwaiee979a142008-09-02 15:42:20 +020016142
16143 err = alc_auto_add_mic_boost(codec);
16144 if (err < 0)
16145 return err;
16146
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016147 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
16148 spec->num_mixers++;
Takashi Iwai8c872862007-06-19 12:11:16 +020016149 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016150}
16151
16152/* additional initialization for auto-configuration model */
16153static void alc662_auto_init(struct hda_codec *codec)
16154{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016155 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016156 alc662_auto_init_multi_out(codec);
16157 alc662_auto_init_hp_out(codec);
16158 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016159 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016160 if (spec->unsol_event)
16161 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016162}
16163
16164static int patch_alc662(struct hda_codec *codec)
16165{
16166 struct alc_spec *spec;
16167 int err, board_config;
16168
16169 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16170 if (!spec)
16171 return -ENOMEM;
16172
16173 codec->spec = spec;
16174
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016175 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16176
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016177 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16178 alc662_models,
16179 alc662_cfg_tbl);
16180 if (board_config < 0) {
16181 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16182 "trying auto-probe from BIOS...\n");
16183 board_config = ALC662_AUTO;
16184 }
16185
16186 if (board_config == ALC662_AUTO) {
16187 /* automatic parse from the BIOS config */
16188 err = alc662_parse_auto_config(codec);
16189 if (err < 0) {
16190 alc_free(codec);
16191 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020016192 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016193 printk(KERN_INFO
16194 "hda_codec: Cannot set up configuration "
16195 "from BIOS. Using base mode...\n");
16196 board_config = ALC662_3ST_2ch_DIG;
16197 }
16198 }
16199
16200 if (board_config != ALC662_AUTO)
16201 setup_preset(spec, &alc662_presets[board_config]);
16202
Kailang Yang6dda9f42008-05-27 12:05:31 +020016203 if (codec->vendor_id == 0x10ec0663) {
16204 spec->stream_name_analog = "ALC663 Analog";
16205 spec->stream_name_digital = "ALC663 Digital";
16206 } else {
16207 spec->stream_name_analog = "ALC662 Analog";
16208 spec->stream_name_digital = "ALC662 Digital";
16209 }
16210
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016211 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16212 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16213
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016214 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16215 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16216
Takashi Iwaie1406342008-02-11 18:32:32 +010016217 spec->adc_nids = alc662_adc_nids;
16218 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16219 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016220
Takashi Iwai2134ea42008-01-10 16:53:55 +010016221 spec->vmaster_nid = 0x02;
16222
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016223 codec->patch_ops = alc_patch_ops;
16224 if (board_config == ALC662_AUTO)
16225 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016226#ifdef CONFIG_SND_HDA_POWER_SAVE
16227 if (!spec->loopback.amplist)
16228 spec->loopback.amplist = alc662_loopbacks;
16229#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016230
16231 return 0;
16232}
16233
16234/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016235 * patch entries
16236 */
16237struct hda_codec_preset snd_hda_preset_realtek[] = {
16238 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016239 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016240 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016241 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016242 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016243 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016244 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016245 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16246 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16247 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016248 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16249 .patch = patch_alc883 },
16250 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16251 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016252 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016253 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016254 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016255 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020016256 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016257 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016258 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016259 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016260 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016261 {} /* terminator */
16262};