blob: ca1a87a4812ce4b6782e7eec5ab456dab6c41c8d [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"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.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,
Michael Schwingencc959482009-02-22 18:58:45 +010081 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010082#ifdef CONFIG_SND_DEBUG
83 ALC260_TEST,
84#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010085 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020086 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Kailang Yangdf694da2005-12-05 19:42:22 +010089/* ALC262 models */
90enum {
91 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020092 ALC262_HIPPO,
93 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010094 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020095 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010096 ALC262_HP_BPC_D7000_WL,
97 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010098 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010099 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200100 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200101 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200102 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200103 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100104 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200105 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200106 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200107 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000108 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100109 ALC262_AUTO,
110 ALC262_MODEL_LAST /* last tag */
111};
112
Kailang Yanga361d842007-06-05 12:30:55 +0200113/* ALC268 models */
114enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200115 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200116 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200117 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200118 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100119 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200120 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100121 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100122 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100123#ifdef CONFIG_SND_DEBUG
124 ALC268_TEST,
125#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200126 ALC268_AUTO,
127 ALC268_MODEL_LAST /* last tag */
128};
129
Kailang Yangf6a92242007-12-13 16:52:54 +0100130/* ALC269 models */
131enum {
132 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200133 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100134 ALC269_AMIC,
135 ALC269_DMIC,
136 ALC269VB_AMIC,
137 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100138 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000139 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100140 ALC269_AUTO,
141 ALC269_MODEL_LAST /* last tag */
142};
143
Kailang Yangdf694da2005-12-05 19:42:22 +0100144/* ALC861 models */
145enum {
146 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200147 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100148 ALC861_3ST_DIG,
149 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200150 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200151 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200152 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100153 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100154 ALC861_AUTO,
155 ALC861_MODEL_LAST,
156};
157
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100158/* ALC861-VD models */
159enum {
160 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200161 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100162 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100163 ALC861VD_3ST,
164 ALC861VD_3ST_DIG,
165 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200166 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200167 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200168 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100169 ALC861VD_AUTO,
170 ALC861VD_MODEL_LAST,
171};
172
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200173/* ALC662 models */
174enum {
175 ALC662_3ST_2ch_DIG,
176 ALC662_3ST_6ch_DIG,
177 ALC662_3ST_6ch,
178 ALC662_5ST_DIG,
179 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200180 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100181 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200182 ALC663_ASUS_M51VA,
183 ALC663_ASUS_G71V,
184 ALC663_ASUS_H13,
185 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200186 ALC662_ECS,
187 ALC663_ASUS_MODE1,
188 ALC662_ASUS_MODE2,
189 ALC663_ASUS_MODE3,
190 ALC663_ASUS_MODE4,
191 ALC663_ASUS_MODE5,
192 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100193 ALC663_ASUS_MODE7,
194 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200195 ALC272_DELL,
196 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200197 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200198 ALC662_AUTO,
199 ALC662_MODEL_LAST,
200};
201
Kailang Yangdf694da2005-12-05 19:42:22 +0100202/* ALC882 models */
203enum {
204 ALC882_3ST_DIG,
205 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200206 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200207 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200208 ALC882_TARGA,
209 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200210 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100211 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800212 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200213 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200214 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100215 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200216 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800217 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200218 ALC883_3ST_2ch_DIG,
219 ALC883_3ST_6ch_DIG,
220 ALC883_3ST_6ch,
221 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200222 ALC883_TARGA_DIG,
223 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200224 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200225 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200226 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800227 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100228 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200229 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200230 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200231 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200232 ALC883_MEDION_MD2,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200233 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100234 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200235 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200236 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200237 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200238 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200239 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200240 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100241 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100242 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430243 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100244 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100245 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800246 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200247 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200248 ALC889A_INTEL,
249 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200250 ALC888_ASUS_M90V,
251 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200252 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100253 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200254 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-06-30 15:28:30 +0200255 ALC882_AUTO,
256 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200257};
258
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200259/* ALC680 models */
260enum {
261 ALC680_BASE,
262 ALC680_AUTO,
263 ALC680_MODEL_LAST,
264};
265
Kailang Yangdf694da2005-12-05 19:42:22 +0100266/* for GPIO Poll */
267#define GPIO_MASK 0x03
268
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200269/* extra amp-initialization sequence types */
270enum {
271 ALC_INIT_NONE,
272 ALC_INIT_DEFAULT,
273 ALC_INIT_GPIO1,
274 ALC_INIT_GPIO2,
275 ALC_INIT_GPIO3,
276};
277
Takashi Iwai6c819492009-08-10 18:47:44 +0200278struct alc_mic_route {
279 hda_nid_t pin;
280 unsigned char mux_idx;
281 unsigned char amix_idx;
282};
283
284#define MUX_IDX_UNDEF ((unsigned char)-1)
285
Kailang Yangda00c242010-03-19 11:23:45 +0100286struct alc_customize_define {
287 unsigned int sku_cfg;
288 unsigned char port_connectivity;
289 unsigned char check_sum;
290 unsigned char customization;
291 unsigned char external_amp;
292 unsigned int enable_pcbeep:1;
293 unsigned int platform_type:1;
294 unsigned int swap:1;
295 unsigned int override:1;
296};
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298struct alc_spec {
299 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100300 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100302 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100303 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200305 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200306 * don't forget NULL
307 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200308 */
309 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200311 char stream_name_analog[32]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct hda_pcm_stream *stream_analog_playback;
313 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100314 struct hda_pcm_stream *stream_analog_alt_playback;
315 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200317 char stream_name_digital[32]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 struct hda_pcm_stream *stream_digital_playback;
319 struct hda_pcm_stream *stream_digital_capture;
320
321 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200322 struct hda_multi_out multiout; /* playback set-up
323 * max_channels, dacs must be set
324 * dig_out_nid and hp_nid are optional
325 */
Takashi Iwai63300792008-01-24 15:31:36 +0100326 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100327 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100328 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 /* capture */
331 unsigned int num_adc_nids;
332 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100333 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200334 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Takashi Iwai840b64c2010-07-13 22:49:01 +0200336 /* capture setup for dynamic dual-adc switch */
337 unsigned int cur_adc_idx;
338 hda_nid_t cur_adc;
339 unsigned int cur_adc_stream_tag;
340 unsigned int cur_adc_format;
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200343 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 const struct hda_input_mux *input_mux;
345 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200346 struct alc_mic_route ext_mic;
347 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100350 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200352 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200353 int const_channel_count;
354 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100357 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200358
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200359 /* dynamic controls, init_verbs and input_mux */
360 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100361 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200362 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200363 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200364 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200365 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
366 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100367
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100368 /* hooks */
369 void (*init_hook)(struct hda_codec *codec);
370 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100371#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500372 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100373#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100374
Takashi Iwai834be882006-03-01 14:16:17 +0100375 /* for pin sensing */
376 unsigned int sense_updated: 1;
377 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100378 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200379 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200380
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100381 /* other flags */
382 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200383 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200384 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100385
Takashi Iwai2134ea42008-01-10 16:53:55 +0100386 /* for virtual master */
387 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200388#ifdef CONFIG_SND_HDA_POWER_SAVE
389 struct hda_loopback_check loopback;
390#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200391
392 /* for PLL fix */
393 hda_nid_t pll_nid;
394 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100395};
396
397/*
398 * configuration template - to be copied to the spec instance
399 */
400struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200401 struct snd_kcontrol_new *mixers[5]; /* should be identical size
402 * with spec
403 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100404 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100405 const struct hda_verb *init_verbs[5];
406 unsigned int num_dacs;
407 hda_nid_t *dac_nids;
408 hda_nid_t dig_out_nid; /* optional */
409 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800410 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100411 unsigned int num_adc_nids;
412 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100413 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100414 hda_nid_t dig_in_nid;
415 unsigned int num_channel_mode;
416 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200417 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200418 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200419 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100420 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100421 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200422 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100423 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200424#ifdef CONFIG_SND_HDA_POWER_SAVE
425 struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500426 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200427#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428};
429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431/*
432 * input MUX handling
433 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200434static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
435 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
438 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200439 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
440 if (mux_idx >= spec->num_mux_defs)
441 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100442 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
443 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200444 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200447static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
451 struct alc_spec *spec = codec->spec;
452 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
453
454 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
455 return 0;
456}
457
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200458static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
459 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
461 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
462 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100463 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100465 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100466 hda_nid_t nid = spec->capsrc_nids ?
467 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200468 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Takashi Iwaicd896c32008-11-18 12:36:33 +0100470 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
471 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100472 if (!imux->num_items && mux_idx > 0)
473 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100474
Takashi Iwaia22d5432009-07-27 12:54:26 +0200475 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200476 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100477 /* Matrix-mixer style (e.g. ALC882) */
478 unsigned int *cur_val = &spec->cur_mux[adc_idx];
479 unsigned int i, idx;
480
481 idx = ucontrol->value.enumerated.item[0];
482 if (idx >= imux->num_items)
483 idx = imux->num_items - 1;
484 if (*cur_val == idx)
485 return 0;
486 for (i = 0; i < imux->num_items; i++) {
487 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
488 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
489 imux->items[i].index,
490 HDA_AMP_MUTE, v);
491 }
492 *cur_val = idx;
493 return 1;
494 } else {
495 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100496 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100497 &spec->cur_mux[adc_idx]);
498 }
499}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
502 * channel mode setting
503 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200504static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
505 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
508 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100509 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
510 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200513static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
514 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
517 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100518 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200519 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200520 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200523static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
524 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
526 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
527 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200528 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
529 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200530 &spec->ext_channel_count);
531 if (err >= 0 && !spec->const_channel_count) {
532 spec->multiout.max_channels = spec->ext_channel_count;
533 if (spec->need_dac_fix)
534 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
535 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200536 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100540 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200541 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100542 * being part of a format specifier. Maximum allowed length of a value is
543 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100544 *
545 * Note: some retasking pin complexes seem to ignore requests for input
546 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
547 * are requested. Therefore order this list so that this behaviour will not
548 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200549 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
550 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200551 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100552static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100553 "Mic 50pc bias", "Mic 80pc bias",
554 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100555};
556static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100557 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100558};
559/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200560 * in the pin being assumed to be exclusively an input or an output pin. In
561 * addition, "input" pins may or may not process the mic bias option
562 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
563 * accept requests for bias as of chip versions up to March 2006) and/or
564 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100565 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200566#define ALC_PIN_DIR_IN 0x00
567#define ALC_PIN_DIR_OUT 0x01
568#define ALC_PIN_DIR_INOUT 0x02
569#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
570#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100571
Kailang Yangea1fb292008-08-26 12:58:38 +0200572/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100573 * For each direction the minimum and maximum values are given.
574 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200575static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100576 { 0, 2 }, /* ALC_PIN_DIR_IN */
577 { 3, 4 }, /* ALC_PIN_DIR_OUT */
578 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200579 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
580 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100581};
582#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
583#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
584#define alc_pin_mode_n_items(_dir) \
585 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
586
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200587static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
588 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200589{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100590 unsigned int item_num = uinfo->value.enumerated.item;
591 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
592
593 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200594 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100595 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
596
597 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
598 item_num = alc_pin_mode_min(dir);
599 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200600 return 0;
601}
602
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200603static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
604 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200605{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100606 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200607 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
608 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100609 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200610 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200611 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
612 AC_VERB_GET_PIN_WIDGET_CONTROL,
613 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200614
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100615 /* Find enumerated value for current pinctl setting */
616 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200617 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100618 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200619 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100620 return 0;
621}
622
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200623static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
624 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100625{
626 signed int change;
627 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
628 hda_nid_t nid = kcontrol->private_value & 0xffff;
629 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
630 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200631 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
632 AC_VERB_GET_PIN_WIDGET_CONTROL,
633 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100634
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200635 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100636 val = alc_pin_mode_min(dir);
637
638 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100639 if (change) {
640 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200641 snd_hda_codec_write_cache(codec, nid, 0,
642 AC_VERB_SET_PIN_WIDGET_CONTROL,
643 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100644
Kailang Yangea1fb292008-08-26 12:58:38 +0200645 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100646 * for the requested pin mode. Enum values of 2 or less are
647 * input modes.
648 *
649 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200650 * reduces noise slightly (particularly on input) so we'll
651 * do it. However, having both input and output buffers
652 * enabled simultaneously doesn't seem to be problematic if
653 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100654 */
655 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200656 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
657 HDA_AMP_MUTE, HDA_AMP_MUTE);
658 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
659 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100660 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200661 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
662 HDA_AMP_MUTE, HDA_AMP_MUTE);
663 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
664 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100665 }
666 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200667 return change;
668}
669
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100670#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200671 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100672 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100673 .info = alc_pin_mode_info, \
674 .get = alc_pin_mode_get, \
675 .put = alc_pin_mode_put, \
676 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100677
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100678/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
679 * together using a mask with more than one bit set. This control is
680 * currently used only by the ALC260 test model. At this stage they are not
681 * needed for any "production" models.
682 */
683#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200684#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200685
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200686static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
687 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100688{
689 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
690 hda_nid_t nid = kcontrol->private_value & 0xffff;
691 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
692 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200693 unsigned int val = snd_hda_codec_read(codec, nid, 0,
694 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100695
696 *valp = (val & mask) != 0;
697 return 0;
698}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200699static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
700 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100701{
702 signed int change;
703 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
704 hda_nid_t nid = kcontrol->private_value & 0xffff;
705 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
706 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200707 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
708 AC_VERB_GET_GPIO_DATA,
709 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100710
711 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200712 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
713 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100714 gpio_data &= ~mask;
715 else
716 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200717 snd_hda_codec_write_cache(codec, nid, 0,
718 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100719
720 return change;
721}
722#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
723 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100724 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100725 .info = alc_gpio_data_info, \
726 .get = alc_gpio_data_get, \
727 .put = alc_gpio_data_put, \
728 .private_value = nid | (mask<<16) }
729#endif /* CONFIG_SND_DEBUG */
730
Jonathan Woithe92621f12006-02-28 11:47:47 +0100731/* A switch control to allow the enabling of the digital IO pins on the
732 * ALC260. This is incredibly simplistic; the intention of this control is
733 * to provide something in the test model allowing digital outputs to be
734 * identified if present. If models are found which can utilise these
735 * outputs a more complete mixer control can be devised for those models if
736 * necessary.
737 */
738#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200739#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200740
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200741static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
742 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100743{
744 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
745 hda_nid_t nid = kcontrol->private_value & 0xffff;
746 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
747 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200748 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100749 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100750
751 *valp = (val & mask) != 0;
752 return 0;
753}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200754static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
755 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100756{
757 signed int change;
758 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
759 hda_nid_t nid = kcontrol->private_value & 0xffff;
760 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
761 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200762 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100763 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200764 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100765
766 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200767 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100768 if (val==0)
769 ctrl_data &= ~mask;
770 else
771 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200772 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
773 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100774
775 return change;
776}
777#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
778 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100779 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100780 .info = alc_spdif_ctrl_info, \
781 .get = alc_spdif_ctrl_get, \
782 .put = alc_spdif_ctrl_put, \
783 .private_value = nid | (mask<<16) }
784#endif /* CONFIG_SND_DEBUG */
785
Jonathan Woithef8225f62008-01-08 12:16:54 +0100786/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
787 * Again, this is only used in the ALC26x test models to help identify when
788 * the EAPD line must be asserted for features to work.
789 */
790#ifdef CONFIG_SND_DEBUG
791#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
792
793static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
794 struct snd_ctl_elem_value *ucontrol)
795{
796 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
797 hda_nid_t nid = kcontrol->private_value & 0xffff;
798 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
799 long *valp = ucontrol->value.integer.value;
800 unsigned int val = snd_hda_codec_read(codec, nid, 0,
801 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
802
803 *valp = (val & mask) != 0;
804 return 0;
805}
806
807static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
808 struct snd_ctl_elem_value *ucontrol)
809{
810 int change;
811 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
812 hda_nid_t nid = kcontrol->private_value & 0xffff;
813 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
814 long val = *ucontrol->value.integer.value;
815 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
816 AC_VERB_GET_EAPD_BTLENABLE,
817 0x00);
818
819 /* Set/unset the masked control bit(s) as needed */
820 change = (!val ? 0 : mask) != (ctrl_data & mask);
821 if (!val)
822 ctrl_data &= ~mask;
823 else
824 ctrl_data |= mask;
825 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
826 ctrl_data);
827
828 return change;
829}
830
831#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
832 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100833 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100834 .info = alc_eapd_ctrl_info, \
835 .get = alc_eapd_ctrl_get, \
836 .put = alc_eapd_ctrl_put, \
837 .private_value = nid | (mask<<16) }
838#endif /* CONFIG_SND_DEBUG */
839
Kailang Yangdf694da2005-12-05 19:42:22 +0100840/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100841 * set up the input pin config (depending on the given auto-pin type)
842 */
843static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
844 int auto_pin_type)
845{
846 unsigned int val = PIN_IN;
847
848 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
849 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100850 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100851 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
852 if (pincap & AC_PINCAP_VREF_80)
853 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200854 else if (pincap & AC_PINCAP_VREF_50)
855 val = PIN_VREF50;
856 else if (pincap & AC_PINCAP_VREF_100)
857 val = PIN_VREF100;
858 else if (pincap & AC_PINCAP_VREF_GRD)
859 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100860 }
861 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
862}
863
864/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100865 */
866static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
867{
868 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
869 return;
870 spec->mixers[spec->num_mixers++] = mix;
871}
872
873static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
874{
875 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
876 return;
877 spec->init_verbs[spec->num_init_verbs++] = verb;
878}
879
880/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100881 * set up from the preset table
882 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200883static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200884 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100885{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200886 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100887 int i;
888
889 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100890 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100891 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200892 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
893 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100894 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200895
Kailang Yangdf694da2005-12-05 19:42:22 +0100896 spec->channel_mode = preset->channel_mode;
897 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200898 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200899 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100900
Hector Martin3b315d72009-06-02 10:54:19 +0200901 if (preset->const_channel_count)
902 spec->multiout.max_channels = preset->const_channel_count;
903 else
904 spec->multiout.max_channels = spec->channel_mode[0].channels;
905 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100906
907 spec->multiout.num_dacs = preset->num_dacs;
908 spec->multiout.dac_nids = preset->dac_nids;
909 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800910 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100911 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200912
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200913 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200914 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200915 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100916 spec->input_mux = preset->input_mux;
917
918 spec->num_adc_nids = preset->num_adc_nids;
919 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100920 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100921 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100922
923 spec->unsol_event = preset->unsol_event;
924 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200925#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100926 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200927 spec->loopback.amplist = preset->loopbacks;
928#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200929
930 if (preset->setup)
931 preset->setup(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100932}
933
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200934/* Enable GPIO mask and set output */
935static struct hda_verb alc_gpio1_init_verbs[] = {
936 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
937 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
938 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
939 { }
940};
941
942static struct hda_verb alc_gpio2_init_verbs[] = {
943 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
944 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
945 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
946 { }
947};
948
Kailang Yangbdd148a2007-05-08 15:19:08 +0200949static struct hda_verb alc_gpio3_init_verbs[] = {
950 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
951 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
952 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
953 { }
954};
955
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200956/*
957 * Fix hardware PLL issue
958 * On some codecs, the analog PLL gating control must be off while
959 * the default value is 1.
960 */
961static void alc_fix_pll(struct hda_codec *codec)
962{
963 struct alc_spec *spec = codec->spec;
964 unsigned int val;
965
966 if (!spec->pll_nid)
967 return;
968 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
969 spec->pll_coef_idx);
970 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
971 AC_VERB_GET_PROC_COEF, 0);
972 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
973 spec->pll_coef_idx);
974 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
975 val & ~(1 << spec->pll_coef_bit));
976}
977
978static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
979 unsigned int coef_idx, unsigned int coef_bit)
980{
981 struct alc_spec *spec = codec->spec;
982 spec->pll_nid = nid;
983 spec->pll_coef_idx = coef_idx;
984 spec->pll_coef_bit = coef_bit;
985 alc_fix_pll(codec);
986}
987
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200988static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200989{
990 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200991 unsigned int nid = spec->autocfg.hp_pins[0];
992 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200993
Takashi Iwaiad87c642009-11-02 14:23:15 +0100994 if (!nid)
995 return;
Wu Fengguang864f92b2009-11-18 12:38:02 +0800996 spec->jack_present = snd_hda_jack_detect(codec, nid);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200997 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
998 nid = spec->autocfg.speaker_pins[i];
999 if (!nid)
1000 break;
1001 snd_hda_codec_write(codec, nid, 0,
1002 AC_VERB_SET_PIN_WIDGET_CONTROL,
1003 spec->jack_present ? 0 : PIN_OUT);
1004 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001005}
1006
Takashi Iwai6c819492009-08-10 18:47:44 +02001007static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1008 hda_nid_t nid)
1009{
1010 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1011 int i, nums;
1012
1013 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1014 for (i = 0; i < nums; i++)
1015 if (conn[i] == nid)
1016 return i;
1017 return -1;
1018}
1019
Takashi Iwai840b64c2010-07-13 22:49:01 +02001020/* switch the current ADC according to the jack state */
1021static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1022{
1023 struct alc_spec *spec = codec->spec;
1024 unsigned int present;
1025 hda_nid_t new_adc;
1026
1027 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1028 if (present)
1029 spec->cur_adc_idx = 1;
1030 else
1031 spec->cur_adc_idx = 0;
1032 new_adc = spec->adc_nids[spec->cur_adc_idx];
1033 if (spec->cur_adc && spec->cur_adc != new_adc) {
1034 /* stream is running, let's swap the current ADC */
1035 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
1036 spec->cur_adc = new_adc;
1037 snd_hda_codec_setup_stream(codec, new_adc,
1038 spec->cur_adc_stream_tag, 0,
1039 spec->cur_adc_format);
1040 }
1041}
1042
Kailang Yang7fb0d782008-10-15 11:12:35 +02001043static void alc_mic_automute(struct hda_codec *codec)
1044{
1045 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001046 struct alc_mic_route *dead, *alive;
1047 unsigned int present, type;
1048 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001049
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001050 if (!spec->auto_mic)
1051 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001052 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1053 return;
1054 if (snd_BUG_ON(!spec->adc_nids))
1055 return;
1056
Takashi Iwai840b64c2010-07-13 22:49:01 +02001057 if (spec->dual_adc_switch) {
1058 alc_dual_mic_adc_auto_switch(codec);
1059 return;
1060 }
1061
Takashi Iwai6c819492009-08-10 18:47:44 +02001062 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1063
Wu Fengguang864f92b2009-11-18 12:38:02 +08001064 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001065 if (present) {
1066 alive = &spec->ext_mic;
1067 dead = &spec->int_mic;
1068 } else {
1069 alive = &spec->int_mic;
1070 dead = &spec->ext_mic;
1071 }
1072
Takashi Iwai6c819492009-08-10 18:47:44 +02001073 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1074 if (type == AC_WID_AUD_MIX) {
1075 /* Matrix-mixer style (e.g. ALC882) */
1076 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1077 alive->mux_idx,
1078 HDA_AMP_MUTE, 0);
1079 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1080 dead->mux_idx,
1081 HDA_AMP_MUTE, HDA_AMP_MUTE);
1082 } else {
1083 /* MUX style (e.g. ALC880) */
1084 snd_hda_codec_write_cache(codec, cap_nid, 0,
1085 AC_VERB_SET_CONNECT_SEL,
1086 alive->mux_idx);
1087 }
1088
1089 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001090}
1091
Kailang Yangc9b58002007-10-16 14:30:01 +02001092/* unsolicited event for HP jack sensing */
1093static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1094{
1095 if (codec->vendor_id == 0x10ec0880)
1096 res >>= 28;
1097 else
1098 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001099 switch (res) {
1100 case ALC880_HP_EVENT:
1101 alc_automute_pin(codec);
1102 break;
1103 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001104 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001105 break;
1106 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001107}
1108
1109static void alc_inithook(struct hda_codec *codec)
1110{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001111 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001112 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001113}
1114
Kailang Yangf9423e72008-05-27 12:32:25 +02001115/* additional initialization for ALC888 variants */
1116static void alc888_coef_init(struct hda_codec *codec)
1117{
1118 unsigned int tmp;
1119
1120 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1121 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1122 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001123 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001124 /* alc888S-VC */
1125 snd_hda_codec_read(codec, 0x20, 0,
1126 AC_VERB_SET_PROC_COEF, 0x830);
1127 else
1128 /* alc888-VB */
1129 snd_hda_codec_read(codec, 0x20, 0,
1130 AC_VERB_SET_PROC_COEF, 0x3030);
1131}
1132
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001133static void alc889_coef_init(struct hda_codec *codec)
1134{
1135 unsigned int tmp;
1136
1137 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1138 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1139 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1140 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1141}
1142
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001143/* turn on/off EAPD control (only if available) */
1144static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1145{
1146 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1147 return;
1148 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1149 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1150 on ? 2 : 0);
1151}
1152
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001153static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001154{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001155 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001156
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001157 switch (type) {
1158 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001159 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1160 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001161 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001162 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1163 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001164 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001165 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1166 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001167 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001168 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001169 case 0x10ec0260:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001170 set_eapd(codec, 0x0f, 1);
1171 set_eapd(codec, 0x10, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001172 break;
1173 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001174 case 0x10ec0267:
1175 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001176 case 0x10ec0269:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001177 case 0x10ec0270:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001178 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001179 case 0x10ec0660:
1180 case 0x10ec0662:
1181 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001182 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001183 case 0x10ec0889:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001184 set_eapd(codec, 0x14, 1);
1185 set_eapd(codec, 0x15, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001186 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001187 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001188 switch (codec->vendor_id) {
1189 case 0x10ec0260:
1190 snd_hda_codec_write(codec, 0x1a, 0,
1191 AC_VERB_SET_COEF_INDEX, 7);
1192 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1193 AC_VERB_GET_PROC_COEF, 0);
1194 snd_hda_codec_write(codec, 0x1a, 0,
1195 AC_VERB_SET_COEF_INDEX, 7);
1196 snd_hda_codec_write(codec, 0x1a, 0,
1197 AC_VERB_SET_PROC_COEF,
1198 tmp | 0x2010);
1199 break;
1200 case 0x10ec0262:
1201 case 0x10ec0880:
1202 case 0x10ec0882:
1203 case 0x10ec0883:
1204 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001205 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001206 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001207 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001208 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001209 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001210 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001211 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001212#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001213 case 0x10ec0267:
1214 case 0x10ec0268:
1215 snd_hda_codec_write(codec, 0x20, 0,
1216 AC_VERB_SET_COEF_INDEX, 7);
1217 tmp = snd_hda_codec_read(codec, 0x20, 0,
1218 AC_VERB_GET_PROC_COEF, 0);
1219 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001220 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001221 snd_hda_codec_write(codec, 0x20, 0,
1222 AC_VERB_SET_PROC_COEF,
1223 tmp | 0x3000);
1224 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001225#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001226 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001227 break;
1228 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001229}
Kailang Yangea1fb292008-08-26 12:58:38 +02001230
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001231static void alc_init_auto_hp(struct hda_codec *codec)
1232{
1233 struct alc_spec *spec = codec->spec;
1234
1235 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001236 return;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001237
Kailang Yangc9b58002007-10-16 14:30:01 +02001238 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001239 if (spec->autocfg.line_out_pins[0] &&
1240 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001241 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001242 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001243 else
1244 return;
1245 }
1246
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001247 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1248 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001249 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1250 AC_VERB_SET_UNSOLICITED_ENABLE,
1251 AC_USRSP_EN | ALC880_HP_EVENT);
1252 spec->unsol_event = alc_sku_unsol_event;
1253}
1254
Takashi Iwai6c819492009-08-10 18:47:44 +02001255static void alc_init_auto_mic(struct hda_codec *codec)
1256{
1257 struct alc_spec *spec = codec->spec;
1258 struct auto_pin_cfg *cfg = &spec->autocfg;
1259 hda_nid_t fixed, ext;
1260 int i;
1261
1262 /* there must be only two mic inputs exclusively */
1263 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
1264 if (cfg->input_pins[i])
1265 return;
1266
1267 fixed = ext = 0;
1268 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
1269 hda_nid_t nid = cfg->input_pins[i];
1270 unsigned int defcfg;
1271 if (!nid)
1272 return;
1273 defcfg = snd_hda_codec_get_pincfg(codec, nid);
1274 switch (get_defcfg_connect(defcfg)) {
1275 case AC_JACK_PORT_FIXED:
1276 if (fixed)
1277 return; /* already occupied */
1278 fixed = nid;
1279 break;
1280 case AC_JACK_PORT_COMPLEX:
1281 if (ext)
1282 return; /* already occupied */
1283 ext = nid;
1284 break;
1285 default:
1286 return; /* invalid entry */
1287 }
1288 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001289 if (!ext || !fixed)
1290 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001291 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1292 return; /* no unsol support */
1293 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1294 ext, fixed);
1295 spec->ext_mic.pin = ext;
1296 spec->int_mic.pin = fixed;
1297 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1298 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1299 spec->auto_mic = 1;
1300 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1301 AC_VERB_SET_UNSOLICITED_ENABLE,
1302 AC_USRSP_EN | ALC880_MIC_EVENT);
1303 spec->unsol_event = alc_sku_unsol_event;
1304}
1305
Kailang Yangda00c242010-03-19 11:23:45 +01001306static int alc_auto_parse_customize_define(struct hda_codec *codec)
1307{
1308 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001309 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001310 struct alc_spec *spec = codec->spec;
1311
1312 ass = codec->subsystem_id & 0xffff;
Takashi Iwaif189efc2010-07-05 17:28:17 +02001313 if (ass != codec->bus->pci->subsystem_device && (ass & 1)) {
1314 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
Kailang Yangda00c242010-03-19 11:23:45 +01001315 goto do_sku;
Takashi Iwaif189efc2010-07-05 17:28:17 +02001316 }
Kailang Yangda00c242010-03-19 11:23:45 +01001317
1318 nid = 0x1d;
1319 if (codec->vendor_id == 0x10ec0260)
1320 nid = 0x17;
1321 ass = snd_hda_codec_get_pincfg(codec, nid);
1322
1323 if (!(ass & 1)) {
1324 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1325 codec->chip_name, ass);
1326 return -1;
1327 }
1328
1329 /* check sum */
1330 tmp = 0;
1331 for (i = 1; i < 16; i++) {
1332 if ((ass >> i) & 1)
1333 tmp++;
1334 }
1335 if (((ass >> 16) & 0xf) != tmp)
1336 return -1;
1337
1338 spec->cdefine.port_connectivity = ass >> 30;
1339 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1340 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1341 spec->cdefine.customization = ass >> 8;
1342do_sku:
1343 spec->cdefine.sku_cfg = ass;
1344 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1345 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1346 spec->cdefine.swap = (ass & 0x2) >> 1;
1347 spec->cdefine.override = ass & 0x1;
1348
1349 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1350 nid, spec->cdefine.sku_cfg);
1351 snd_printd("SKU: port_connectivity=0x%x\n",
1352 spec->cdefine.port_connectivity);
1353 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1354 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1355 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1356 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1357 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1358 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1359 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1360
1361 return 0;
1362}
1363
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001364/* check subsystem ID and set up device-specific initialization;
1365 * return 1 if initialized, 0 if invalid SSID
1366 */
1367/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1368 * 31 ~ 16 : Manufacture ID
1369 * 15 ~ 8 : SKU ID
1370 * 7 ~ 0 : Assembly ID
1371 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1372 */
1373static int alc_subsystem_id(struct hda_codec *codec,
1374 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001375 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001376{
1377 unsigned int ass, tmp, i;
1378 unsigned nid;
1379 struct alc_spec *spec = codec->spec;
1380
1381 ass = codec->subsystem_id & 0xffff;
1382 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1383 goto do_sku;
1384
1385 /* invalid SSID, check the special NID pin defcfg instead */
1386 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001387 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001388 * 29~21 : reserve
1389 * 20 : PCBEEP input
1390 * 19~16 : Check sum (15:1)
1391 * 15~1 : Custom
1392 * 0 : override
1393 */
1394 nid = 0x1d;
1395 if (codec->vendor_id == 0x10ec0260)
1396 nid = 0x17;
1397 ass = snd_hda_codec_get_pincfg(codec, nid);
1398 snd_printd("realtek: No valid SSID, "
1399 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001400 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001401 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001402 return 0;
1403 if ((ass >> 30) != 1) /* no physical connection */
1404 return 0;
1405
1406 /* check sum */
1407 tmp = 0;
1408 for (i = 1; i < 16; i++) {
1409 if ((ass >> i) & 1)
1410 tmp++;
1411 }
1412 if (((ass >> 16) & 0xf) != tmp)
1413 return 0;
1414do_sku:
1415 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1416 ass & 0xffff, codec->vendor_id);
1417 /*
1418 * 0 : override
1419 * 1 : Swap Jack
1420 * 2 : 0 --> Desktop, 1 --> Laptop
1421 * 3~5 : External Amplifier control
1422 * 7~6 : Reserved
1423 */
1424 tmp = (ass & 0x38) >> 3; /* external Amp control */
1425 switch (tmp) {
1426 case 1:
1427 spec->init_amp = ALC_INIT_GPIO1;
1428 break;
1429 case 3:
1430 spec->init_amp = ALC_INIT_GPIO2;
1431 break;
1432 case 7:
1433 spec->init_amp = ALC_INIT_GPIO3;
1434 break;
1435 case 5:
1436 spec->init_amp = ALC_INIT_DEFAULT;
1437 break;
1438 }
1439
1440 /* is laptop or Desktop and enable the function "Mute internal speaker
1441 * when the external headphone out jack is plugged"
1442 */
1443 if (!(ass & 0x8000))
1444 return 1;
1445 /*
1446 * 10~8 : Jack location
1447 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1448 * 14~13: Resvered
1449 * 15 : 1 --> enable the function "Mute internal speaker
1450 * when the external headphone out jack is plugged"
1451 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001452 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001453 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001454 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1455 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001456 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001457 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001458 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001459 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001460 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001461 else if (tmp == 3)
1462 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001463 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001464 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001465 for (i = 0; i < spec->autocfg.line_outs; i++)
1466 if (spec->autocfg.line_out_pins[i] == nid)
1467 return 1;
1468 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001469 }
1470
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001471 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001472 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001473 return 1;
1474}
Kailang Yangea1fb292008-08-26 12:58:38 +02001475
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001476static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001477 hda_nid_t porta, hda_nid_t porte,
1478 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001479{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001480 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001481 struct alc_spec *spec = codec->spec;
1482 snd_printd("realtek: "
1483 "Enable default setup for auto mode as fallback\n");
1484 spec->init_amp = ALC_INIT_DEFAULT;
1485 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001486 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001487 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001488}
1489
Takashi Iwai41e41f12005-06-08 14:48:49 +02001490/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001491 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001492 */
1493
1494struct alc_pincfg {
1495 hda_nid_t nid;
1496 u32 val;
1497};
1498
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001499struct alc_fixup {
1500 const struct alc_pincfg *pins;
1501 const struct hda_verb *verbs;
1502};
1503
1504static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaif95474e2007-07-10 00:47:43 +02001505 const struct snd_pci_quirk *quirk,
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001506 const struct alc_fixup *fix,
1507 int pre_init)
Takashi Iwaif95474e2007-07-10 00:47:43 +02001508{
1509 const struct alc_pincfg *cfg;
1510
1511 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1512 if (!quirk)
1513 return;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001514 fix += quirk->value;
1515 cfg = fix->pins;
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001516 if (pre_init && cfg) {
1517#ifdef CONFIG_SND_DEBUG_VERBOSE
1518 snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
1519 codec->chip_name, quirk->name);
1520#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001521 for (; cfg->nid; cfg++)
1522 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
1523 }
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001524 if (!pre_init && fix->verbs) {
1525#ifdef CONFIG_SND_DEBUG_VERBOSE
1526 snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
1527 codec->chip_name, quirk->name);
1528#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001529 add_verb(codec->spec, fix->verbs);
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001530 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001531}
1532
Kailang Yang274693f2009-12-03 10:07:50 +01001533static int alc_read_coef_idx(struct hda_codec *codec,
1534 unsigned int coef_idx)
1535{
1536 unsigned int val;
1537 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1538 coef_idx);
1539 val = snd_hda_codec_read(codec, 0x20, 0,
1540 AC_VERB_GET_PROC_COEF, 0);
1541 return val;
1542}
1543
Takashi Iwaif95474e2007-07-10 00:47:43 +02001544/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001545 * ALC888
1546 */
1547
1548/*
1549 * 2ch mode
1550 */
1551static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1552/* Mic-in jack as mic in */
1553 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1554 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1555/* Line-in jack as Line in */
1556 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1557 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1558/* Line-Out as Front */
1559 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1560 { } /* end */
1561};
1562
1563/*
1564 * 4ch mode
1565 */
1566static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1567/* Mic-in jack as mic in */
1568 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1569 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1570/* Line-in jack as Surround */
1571 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1572 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1573/* Line-Out as Front */
1574 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1575 { } /* end */
1576};
1577
1578/*
1579 * 6ch mode
1580 */
1581static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1582/* Mic-in jack as CLFE */
1583 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1584 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1585/* Line-in jack as Surround */
1586 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1587 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1588/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1589 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1590 { } /* end */
1591};
1592
1593/*
1594 * 8ch mode
1595 */
1596static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1597/* Mic-in jack as CLFE */
1598 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1599 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1600/* Line-in jack as Surround */
1601 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1602 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1603/* Line-Out as Side */
1604 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1605 { } /* end */
1606};
1607
1608static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1609 { 2, alc888_4ST_ch2_intel_init },
1610 { 4, alc888_4ST_ch4_intel_init },
1611 { 6, alc888_4ST_ch6_intel_init },
1612 { 8, alc888_4ST_ch8_intel_init },
1613};
1614
1615/*
1616 * ALC888 Fujitsu Siemens Amillo xa3530
1617 */
1618
1619static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1620/* Front Mic: set to PIN_IN (empty by default) */
1621 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1622/* Connect Internal HP to Front */
1623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1624 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1625 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1626/* Connect Bass HP to Front */
1627 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1628 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1629 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1630/* Connect Line-Out side jack (SPDIF) to Side */
1631 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1632 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1633 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1634/* Connect Mic jack to CLFE */
1635 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1636 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1637 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1638/* Connect Line-in jack to Surround */
1639 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1640 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1641 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1642/* Connect HP out jack to Front */
1643 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1644 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1645 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1646/* Enable unsolicited event for HP jack and Line-out jack */
1647 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1648 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1649 {}
1650};
1651
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001652static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001653{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001654 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001655 unsigned int mute;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001656 hda_nid_t nid;
1657 int i;
1658
1659 spec->jack_present = 0;
1660 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1661 nid = spec->autocfg.hp_pins[i];
1662 if (!nid)
1663 break;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001664 if (snd_hda_jack_detect(codec, nid)) {
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001665 spec->jack_present = 1;
1666 break;
1667 }
1668 }
1669
1670 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001671 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001672 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1673 nid = spec->autocfg.speaker_pins[i];
1674 if (!nid)
1675 break;
1676 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1677 HDA_AMP_MUTE, mute);
1678 }
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001679}
1680
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001681static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1682 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001683{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001684 if (codec->vendor_id == 0x10ec0880)
1685 res >>= 28;
1686 else
1687 res >>= 26;
1688 if (res == ALC880_HP_EVENT)
1689 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001690}
1691
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001692static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001693{
1694 struct alc_spec *spec = codec->spec;
1695
1696 spec->autocfg.hp_pins[0] = 0x15;
1697 spec->autocfg.speaker_pins[0] = 0x14;
1698 spec->autocfg.speaker_pins[1] = 0x16;
1699 spec->autocfg.speaker_pins[2] = 0x17;
1700 spec->autocfg.speaker_pins[3] = 0x19;
1701 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001702}
1703
1704static void alc889_intel_init_hook(struct hda_codec *codec)
1705{
1706 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001707 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001708}
1709
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001710static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001711{
1712 struct alc_spec *spec = codec->spec;
1713
1714 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1715 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1716 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1717 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001718}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001719
1720/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001721 * ALC888 Acer Aspire 4930G model
1722 */
1723
1724static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1725/* Front Mic: set to PIN_IN (empty by default) */
1726 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1727/* Unselect Front Mic by default in input mixer 3 */
1728 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001729/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001730 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1731/* Connect Internal HP to front */
1732 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1733 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1734 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1735/* Connect HP out to front */
1736 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1737 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1738 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1739 { }
1740};
1741
Hector Martin3b315d72009-06-02 10:54:19 +02001742/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01001743 * ALC888 Acer Aspire 6530G model
1744 */
1745
1746static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01001747/* Route to built-in subwoofer as well as speakers */
1748 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1749 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1750 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1751 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001752/* Bias voltage on for external mic port */
1753 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02001754/* Front Mic: set to PIN_IN (empty by default) */
1755 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1756/* Unselect Front Mic by default in input mixer 3 */
1757 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001758/* Enable unsolicited event for HP jack */
1759 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1760/* Enable speaker output */
1761 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1762 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01001763 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001764/* Enable headphone output */
1765 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
1766 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1767 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01001768 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001769 { }
1770};
1771
1772/*
Hector Martin018df412009-06-04 00:13:40 +02001773 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001774 */
1775
Hector Martin018df412009-06-04 00:13:40 +02001776static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001777/* Front Mic: set to PIN_IN (empty by default) */
1778 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1779/* Unselect Front Mic by default in input mixer 3 */
1780 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1781/* Enable unsolicited event for HP jack */
1782 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1783/* Connect Internal Front to Front */
1784 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1786 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1787/* Connect Internal Rear to Rear */
1788 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1789 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1790 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1791/* Connect Internal CLFE to CLFE */
1792 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1793 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1794 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1795/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02001796 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02001797 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1798 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1799/* Enable all DACs */
1800/* DAC DISABLE/MUTE 1? */
1801/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
1802 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
1803 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1804/* DAC DISABLE/MUTE 2? */
1805/* some bit here disables the other DACs. Init=0x4900 */
1806 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
1807 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02001808/* DMIC fix
1809 * This laptop has a stereo digital microphone. The mics are only 1cm apart
1810 * which makes the stereo useless. However, either the mic or the ALC889
1811 * makes the signal become a difference/sum signal instead of standard
1812 * stereo, which is annoying. So instead we flip this bit which makes the
1813 * codec replicate the sum signal to both channels, turning it into a
1814 * normal mono mic.
1815 */
1816/* DMIC_CONTROL? Init value = 0x0001 */
1817 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
1818 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02001819 { }
1820};
1821
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001822static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001823 /* Front mic only available on one ADC */
1824 {
1825 .num_items = 4,
1826 .items = {
1827 { "Mic", 0x0 },
1828 { "Line", 0x2 },
1829 { "CD", 0x4 },
1830 { "Front Mic", 0xb },
1831 },
1832 },
1833 {
1834 .num_items = 3,
1835 .items = {
1836 { "Mic", 0x0 },
1837 { "Line", 0x2 },
1838 { "CD", 0x4 },
1839 },
1840 }
1841};
1842
Tony Vroond2fd4b02009-06-21 00:40:10 +01001843static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
1844 /* Interal mic only available on one ADC */
1845 {
Tony Vroon684a8842009-06-26 09:27:50 +01001846 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001847 .items = {
1848 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001849 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001850 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001851 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001852 { "Int Mic", 0xb },
1853 },
1854 },
1855 {
Tony Vroon684a8842009-06-26 09:27:50 +01001856 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001857 .items = {
1858 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001859 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001860 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001861 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001862 },
1863 }
1864};
1865
Hector Martin018df412009-06-04 00:13:40 +02001866static struct hda_input_mux alc889_capture_sources[3] = {
1867 /* Digital mic only available on first "ADC" */
1868 {
1869 .num_items = 5,
1870 .items = {
1871 { "Mic", 0x0 },
1872 { "Line", 0x2 },
1873 { "CD", 0x4 },
1874 { "Front Mic", 0xb },
1875 { "Input Mix", 0xa },
1876 },
1877 },
1878 {
1879 .num_items = 4,
1880 .items = {
1881 { "Mic", 0x0 },
1882 { "Line", 0x2 },
1883 { "CD", 0x4 },
1884 { "Input Mix", 0xa },
1885 },
1886 },
1887 {
1888 .num_items = 4,
1889 .items = {
1890 { "Mic", 0x0 },
1891 { "Line", 0x2 },
1892 { "CD", 0x4 },
1893 { "Input Mix", 0xa },
1894 },
1895 }
1896};
1897
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001898static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001899 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1900 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1901 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1902 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1903 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1904 HDA_OUTPUT),
1905 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1906 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1907 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1908 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1909 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1910 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1911 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1912 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1913 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1914 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1915 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1916 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001917 { } /* end */
1918};
1919
Hector Martin556eea92009-12-20 22:51:23 +01001920static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
1921 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1922 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1923 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1924 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1925 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1926 HDA_OUTPUT),
1927 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1928 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1929 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1930 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1931 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1932 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1933 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1934 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1935 { } /* end */
1936};
1937
1938
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001939static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001940{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001941 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001942
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001943 spec->autocfg.hp_pins[0] = 0x15;
1944 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01001945 spec->autocfg.speaker_pins[1] = 0x16;
1946 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001947}
1948
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001949static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02001950{
1951 struct alc_spec *spec = codec->spec;
1952
1953 spec->autocfg.hp_pins[0] = 0x15;
1954 spec->autocfg.speaker_pins[0] = 0x14;
1955 spec->autocfg.speaker_pins[1] = 0x16;
1956 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02001957}
1958
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001959static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02001960{
1961 struct alc_spec *spec = codec->spec;
1962
1963 spec->autocfg.hp_pins[0] = 0x15;
1964 spec->autocfg.speaker_pins[0] = 0x14;
1965 spec->autocfg.speaker_pins[1] = 0x16;
1966 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02001967}
1968
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001969/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001970 * ALC880 3-stack model
1971 *
1972 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001973 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1974 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 */
1976
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001977static hda_nid_t alc880_dac_nids[4] = {
1978 /* front, rear, clfe, rear_surr */
1979 0x02, 0x05, 0x04, 0x03
1980};
1981
1982static hda_nid_t alc880_adc_nids[3] = {
1983 /* ADC0-2 */
1984 0x07, 0x08, 0x09,
1985};
1986
1987/* The datasheet says the node 0x07 is connected from inputs,
1988 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001989 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001991static hda_nid_t alc880_adc_nids_alt[2] = {
1992 /* ADC1-2 */
1993 0x08, 0x09,
1994};
1995
1996#define ALC880_DIGOUT_NID 0x06
1997#define ALC880_DIGIN_NID 0x0a
1998
1999static struct hda_input_mux alc880_capture_source = {
2000 .num_items = 4,
2001 .items = {
2002 { "Mic", 0x0 },
2003 { "Front Mic", 0x3 },
2004 { "Line", 0x2 },
2005 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002007};
2008
2009/* channel source setting (2/6 channel selection for 3-stack) */
2010/* 2ch mode */
2011static struct hda_verb alc880_threestack_ch2_init[] = {
2012 /* set line-in to input, mute it */
2013 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2014 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2015 /* set mic-in to input vref 80%, mute it */
2016 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2017 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 { } /* end */
2019};
2020
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002021/* 6ch mode */
2022static struct hda_verb alc880_threestack_ch6_init[] = {
2023 /* set line-in to output, unmute it */
2024 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2025 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2026 /* set mic-in to output, unmute it */
2027 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2028 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2029 { } /* end */
2030};
2031
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002032static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002033 { 2, alc880_threestack_ch2_init },
2034 { 6, alc880_threestack_ch6_init },
2035};
2036
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002037static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002038 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002039 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002040 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002041 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002042 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2043 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002044 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2045 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2047 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2048 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2049 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2050 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2051 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2052 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2053 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002055 {
2056 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2057 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002058 .info = alc_ch_mode_info,
2059 .get = alc_ch_mode_get,
2060 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002061 },
2062 { } /* end */
2063};
2064
2065/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002066static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2067 struct snd_ctl_elem_info *uinfo)
2068{
2069 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2070 struct alc_spec *spec = codec->spec;
2071 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002072
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002073 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002074 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2075 HDA_INPUT);
2076 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002077 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002078 return err;
2079}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002081static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2082 unsigned int size, unsigned int __user *tlv)
2083{
2084 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2085 struct alc_spec *spec = codec->spec;
2086 int err;
2087
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002088 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002089 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2090 HDA_INPUT);
2091 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002092 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002093 return err;
2094}
2095
2096typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2097 struct snd_ctl_elem_value *ucontrol);
2098
2099static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2100 struct snd_ctl_elem_value *ucontrol,
2101 getput_call_t func)
2102{
2103 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2104 struct alc_spec *spec = codec->spec;
2105 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2106 int err;
2107
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002108 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002109 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2110 3, 0, HDA_INPUT);
2111 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002112 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002113 return err;
2114}
2115
2116static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2117 struct snd_ctl_elem_value *ucontrol)
2118{
2119 return alc_cap_getput_caller(kcontrol, ucontrol,
2120 snd_hda_mixer_amp_volume_get);
2121}
2122
2123static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2124 struct snd_ctl_elem_value *ucontrol)
2125{
2126 return alc_cap_getput_caller(kcontrol, ucontrol,
2127 snd_hda_mixer_amp_volume_put);
2128}
2129
2130/* capture mixer elements */
2131#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2132
2133static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2134 struct snd_ctl_elem_value *ucontrol)
2135{
2136 return alc_cap_getput_caller(kcontrol, ucontrol,
2137 snd_hda_mixer_amp_switch_get);
2138}
2139
2140static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2141 struct snd_ctl_elem_value *ucontrol)
2142{
2143 return alc_cap_getput_caller(kcontrol, ucontrol,
2144 snd_hda_mixer_amp_switch_put);
2145}
2146
Takashi Iwaia23b6882009-03-23 15:21:36 +01002147#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002148 { \
2149 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2150 .name = "Capture Switch", \
2151 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2152 .count = num, \
2153 .info = alc_cap_sw_info, \
2154 .get = alc_cap_sw_get, \
2155 .put = alc_cap_sw_put, \
2156 }, \
2157 { \
2158 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2159 .name = "Capture Volume", \
2160 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2161 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2162 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2163 .count = num, \
2164 .info = alc_cap_vol_info, \
2165 .get = alc_cap_vol_get, \
2166 .put = alc_cap_vol_put, \
2167 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002168 }
2169
2170#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002171 { \
2172 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2173 /* .name = "Capture Source", */ \
2174 .name = "Input Source", \
2175 .count = num, \
2176 .info = alc_mux_enum_info, \
2177 .get = alc_mux_enum_get, \
2178 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002179 }
2180
2181#define DEFINE_CAPMIX(num) \
2182static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2183 _DEFINE_CAPMIX(num), \
2184 _DEFINE_CAPSRC(num), \
2185 { } /* end */ \
2186}
2187
2188#define DEFINE_CAPMIX_NOSRC(num) \
2189static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2190 _DEFINE_CAPMIX(num), \
2191 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002192}
2193
2194/* up to three ADCs */
2195DEFINE_CAPMIX(1);
2196DEFINE_CAPMIX(2);
2197DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002198DEFINE_CAPMIX_NOSRC(1);
2199DEFINE_CAPMIX_NOSRC(2);
2200DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002201
2202/*
2203 * ALC880 5-stack model
2204 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002205 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2206 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002207 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2208 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2209 */
2210
2211/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002212static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002213 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002214 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 { } /* end */
2216};
2217
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002218/* channel source setting (6/8 channel selection for 5-stack) */
2219/* 6ch mode */
2220static struct hda_verb alc880_fivestack_ch6_init[] = {
2221 /* set line-in to input, mute it */
2222 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2223 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002224 { } /* end */
2225};
2226
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002227/* 8ch mode */
2228static struct hda_verb alc880_fivestack_ch8_init[] = {
2229 /* set line-in to output, unmute it */
2230 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2231 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2232 { } /* end */
2233};
2234
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002235static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002236 { 6, alc880_fivestack_ch6_init },
2237 { 8, alc880_fivestack_ch8_init },
2238};
2239
2240
2241/*
2242 * ALC880 6-stack model
2243 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002244 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2245 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002246 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2247 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2248 */
2249
2250static hda_nid_t alc880_6st_dac_nids[4] = {
2251 /* front, rear, clfe, rear_surr */
2252 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002253};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002254
2255static struct hda_input_mux alc880_6stack_capture_source = {
2256 .num_items = 4,
2257 .items = {
2258 { "Mic", 0x0 },
2259 { "Front Mic", 0x1 },
2260 { "Line", 0x2 },
2261 { "CD", 0x4 },
2262 },
2263};
2264
2265/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002266static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002267 { 8, NULL },
2268};
2269
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002270static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002271 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002272 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002273 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002274 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002275 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2276 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002277 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2278 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002279 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002280 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002281 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2282 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2283 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2284 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2285 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2286 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2287 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2288 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002289 {
2290 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2291 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002292 .info = alc_ch_mode_info,
2293 .get = alc_ch_mode_get,
2294 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002295 },
2296 { } /* end */
2297};
2298
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002299
2300/*
2301 * ALC880 W810 model
2302 *
2303 * W810 has rear IO for:
2304 * Front (DAC 02)
2305 * Surround (DAC 03)
2306 * Center/LFE (DAC 04)
2307 * Digital out (06)
2308 *
2309 * The system also has a pair of internal speakers, and a headphone jack.
2310 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002311 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002312 * There is a variable resistor to control the speaker or headphone
2313 * volume. This is a hardware-only device without a software API.
2314 *
2315 * Plugging headphones in will disable the internal speakers. This is
2316 * implemented in hardware, not via the driver using jack sense. In
2317 * a similar fashion, plugging into the rear socket marked "front" will
2318 * disable both the speakers and headphones.
2319 *
2320 * For input, there's a microphone jack, and an "audio in" jack.
2321 * These may not do anything useful with this driver yet, because I
2322 * haven't setup any initialization verbs for these yet...
2323 */
2324
2325static hda_nid_t alc880_w810_dac_nids[3] = {
2326 /* front, rear/surround, clfe */
2327 0x02, 0x03, 0x04
2328};
2329
2330/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002331static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002332 { 6, NULL }
2333};
2334
2335/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002336static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002337 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002338 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002339 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002340 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002341 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2342 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002343 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2344 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002345 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2346 { } /* end */
2347};
2348
2349
2350/*
2351 * Z710V model
2352 *
2353 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002354 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2355 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002356 */
2357
2358static hda_nid_t alc880_z71v_dac_nids[1] = {
2359 0x02
2360};
2361#define ALC880_Z71V_HP_DAC 0x03
2362
2363/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002364static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002365 { 2, NULL }
2366};
2367
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002368static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002369 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002370 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002371 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002372 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002373 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2374 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2375 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2376 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2377 { } /* end */
2378};
2379
2380
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002381/*
2382 * ALC880 F1734 model
2383 *
2384 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2385 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2386 */
2387
2388static hda_nid_t alc880_f1734_dac_nids[1] = {
2389 0x03
2390};
2391#define ALC880_F1734_HP_DAC 0x02
2392
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002393static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002394 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002395 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002396 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2397 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002398 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2399 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002400 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2401 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002402 { } /* end */
2403};
2404
Takashi Iwai937b4162008-02-11 14:52:36 +01002405static struct hda_input_mux alc880_f1734_capture_source = {
2406 .num_items = 2,
2407 .items = {
2408 { "Mic", 0x1 },
2409 { "CD", 0x4 },
2410 },
2411};
2412
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002413
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002414/*
2415 * ALC880 ASUS model
2416 *
2417 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2418 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2419 * Mic = 0x18, Line = 0x1a
2420 */
2421
2422#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2423#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2424
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002425static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002426 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002427 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002428 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002429 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002430 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2431 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002432 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2433 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002434 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2435 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2436 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2437 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2438 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2439 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002440 {
2441 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2442 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002443 .info = alc_ch_mode_info,
2444 .get = alc_ch_mode_get,
2445 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002446 },
2447 { } /* end */
2448};
2449
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002450/*
2451 * ALC880 ASUS W1V model
2452 *
2453 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2454 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2455 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2456 */
2457
2458/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002459static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002460 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2461 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002462 { } /* end */
2463};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002464
Kailang Yangdf694da2005-12-05 19:42:22 +01002465/* TCL S700 */
2466static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2467 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2468 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2469 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2470 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2471 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2472 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2473 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2474 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2475 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002476 { } /* end */
2477};
2478
Kailang Yangccc656c2006-10-17 12:32:26 +02002479/* Uniwill */
2480static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002481 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2482 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2483 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2484 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002485 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2486 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2487 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2488 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2489 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2490 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2491 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2492 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2493 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2494 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2495 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2496 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002497 {
2498 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2499 .name = "Channel Mode",
2500 .info = alc_ch_mode_info,
2501 .get = alc_ch_mode_get,
2502 .put = alc_ch_mode_put,
2503 },
2504 { } /* end */
2505};
2506
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002507static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2508 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2509 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2510 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2511 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2512 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2513 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2514 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2515 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2516 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2517 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2518 { } /* end */
2519};
2520
Kailang Yangccc656c2006-10-17 12:32:26 +02002521static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002522 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2523 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2524 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2525 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002526 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2527 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2528 { } /* end */
2529};
2530
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002532 * virtual master controls
2533 */
2534
2535/*
2536 * slave controls for virtual master
2537 */
2538static const char *alc_slave_vols[] = {
2539 "Front Playback Volume",
2540 "Surround Playback Volume",
2541 "Center Playback Volume",
2542 "LFE Playback Volume",
2543 "Side Playback Volume",
2544 "Headphone Playback Volume",
2545 "Speaker Playback Volume",
2546 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002547 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002548 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002549 NULL,
2550};
2551
2552static const char *alc_slave_sws[] = {
2553 "Front Playback Switch",
2554 "Surround Playback Switch",
2555 "Center Playback Switch",
2556 "LFE Playback Switch",
2557 "Side Playback Switch",
2558 "Headphone Playback Switch",
2559 "Speaker Playback Switch",
2560 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002561 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002562 "Line-Out Playback Switch",
2563 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002564 NULL,
2565};
2566
2567/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002568 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002570
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002571#define NID_MAPPING (-1)
2572
2573#define SUBDEV_SPEAKER_ (0 << 6)
2574#define SUBDEV_HP_ (1 << 6)
2575#define SUBDEV_LINE_ (2 << 6)
2576#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2577#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2578#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2579
Takashi Iwai603c4012008-07-30 15:01:44 +02002580static void alc_free_kctls(struct hda_codec *codec);
2581
Takashi Iwai67d634c2009-11-16 15:35:59 +01002582#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002583/* additional beep mixers; the actual parameters are overwritten at build */
2584static struct snd_kcontrol_new alc_beep_mixer[] = {
2585 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002586 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002587 { } /* end */
2588};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002589#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591static int alc_build_controls(struct hda_codec *codec)
2592{
2593 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002594 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002595 struct snd_kcontrol_new *knew;
2596 int i, j, err;
2597 unsigned int u;
2598 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599
2600 for (i = 0; i < spec->num_mixers; i++) {
2601 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2602 if (err < 0)
2603 return err;
2604 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002605 if (spec->cap_mixer) {
2606 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2607 if (err < 0)
2608 return err;
2609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002611 err = snd_hda_create_spdif_out_ctls(codec,
2612 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 if (err < 0)
2614 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002615 if (!spec->no_analog) {
2616 err = snd_hda_create_spdif_share_sw(codec,
2617 &spec->multiout);
2618 if (err < 0)
2619 return err;
2620 spec->multiout.share_spdif = 1;
2621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 }
2623 if (spec->dig_in_nid) {
2624 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2625 if (err < 0)
2626 return err;
2627 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002628
Takashi Iwai67d634c2009-11-16 15:35:59 +01002629#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002630 /* create beep controls if needed */
2631 if (spec->beep_amp) {
2632 struct snd_kcontrol_new *knew;
2633 for (knew = alc_beep_mixer; knew->name; knew++) {
2634 struct snd_kcontrol *kctl;
2635 kctl = snd_ctl_new1(knew, codec);
2636 if (!kctl)
2637 return -ENOMEM;
2638 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002639 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002640 if (err < 0)
2641 return err;
2642 }
2643 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002644#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002645
Takashi Iwai2134ea42008-01-10 16:53:55 +01002646 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002647 if (!spec->no_analog &&
2648 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002649 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002650 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002651 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002652 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002653 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002654 if (err < 0)
2655 return err;
2656 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002657 if (!spec->no_analog &&
2658 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002659 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2660 NULL, alc_slave_sws);
2661 if (err < 0)
2662 return err;
2663 }
2664
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002665 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02002666 if (spec->capsrc_nids || spec->adc_nids) {
2667 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2668 if (!kctl)
2669 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2670 for (i = 0; kctl && i < kctl->count; i++) {
2671 hda_nid_t *nids = spec->capsrc_nids;
2672 if (!nids)
2673 nids = spec->adc_nids;
2674 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
2675 if (err < 0)
2676 return err;
2677 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002678 }
2679 if (spec->cap_mixer) {
2680 const char *kname = kctl ? kctl->id.name : NULL;
2681 for (knew = spec->cap_mixer; knew->name; knew++) {
2682 if (kname && strcmp(knew->name, kname) == 0)
2683 continue;
2684 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2685 for (i = 0; kctl && i < kctl->count; i++) {
2686 err = snd_hda_add_nid(codec, kctl, i,
2687 spec->adc_nids[i]);
2688 if (err < 0)
2689 return err;
2690 }
2691 }
2692 }
2693
2694 /* other nid->control mapping */
2695 for (i = 0; i < spec->num_mixers; i++) {
2696 for (knew = spec->mixers[i]; knew->name; knew++) {
2697 if (knew->iface != NID_MAPPING)
2698 continue;
2699 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2700 if (kctl == NULL)
2701 continue;
2702 u = knew->subdevice;
2703 for (j = 0; j < 4; j++, u >>= 8) {
2704 nid = u & 0x3f;
2705 if (nid == 0)
2706 continue;
2707 switch (u & 0xc0) {
2708 case SUBDEV_SPEAKER_:
2709 nid = spec->autocfg.speaker_pins[nid];
2710 break;
2711 case SUBDEV_LINE_:
2712 nid = spec->autocfg.line_out_pins[nid];
2713 break;
2714 case SUBDEV_HP_:
2715 nid = spec->autocfg.hp_pins[nid];
2716 break;
2717 default:
2718 continue;
2719 }
2720 err = snd_hda_add_nid(codec, kctl, 0, nid);
2721 if (err < 0)
2722 return err;
2723 }
2724 u = knew->private_value;
2725 for (j = 0; j < 4; j++, u >>= 8) {
2726 nid = u & 0xff;
2727 if (nid == 0)
2728 continue;
2729 err = snd_hda_add_nid(codec, kctl, 0, nid);
2730 if (err < 0)
2731 return err;
2732 }
2733 }
2734 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01002735
2736 alc_free_kctls(codec); /* no longer needed */
2737
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 return 0;
2739}
2740
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002741
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742/*
2743 * initialize the codec volumes, etc
2744 */
2745
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002746/*
2747 * generic initialization of ADC, input mixers and output mixers
2748 */
2749static struct hda_verb alc880_volume_init_verbs[] = {
2750 /*
2751 * Unmute ADC0-2 and set the default input to mic-in
2752 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002753 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002754 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002755 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002756 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002757 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002758 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002760 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2761 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002762 * Note: PASD motherboards uses the Line In 2 as the input for front
2763 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002765 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002766 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2767 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2768 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2769 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2770 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2771 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2772 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002774 /*
2775 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002777 /* set vol=0 to output mixers */
2778 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2779 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2780 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2781 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2782 /* set up input amps for analog loopback */
2783 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002784 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2785 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002786 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2787 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002788 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2789 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002790 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2791 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 { }
2794};
2795
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002796/*
2797 * 3-stack pin configuration:
2798 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2799 */
2800static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2801 /*
2802 * preset connection lists of input pins
2803 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2804 */
2805 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2806 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2807 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2808
2809 /*
2810 * Set pin mode and muting
2811 */
2812 /* set front pin widgets 0x14 for output */
2813 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2814 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2815 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2816 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2817 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2818 /* Mic2 (as headphone out) for HP output */
2819 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2820 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2821 /* Line In pin widget for input */
2822 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2823 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2824 /* Line2 (as front mic) pin widget for input and vref at 80% */
2825 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2826 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2827 /* CD pin widget for input */
2828 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2829
2830 { }
2831};
2832
2833/*
2834 * 5-stack pin configuration:
2835 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2836 * line-in/side = 0x1a, f-mic = 0x1b
2837 */
2838static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2839 /*
2840 * preset connection lists of input pins
2841 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2842 */
2843 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2844 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2845
2846 /*
2847 * Set pin mode and muting
2848 */
2849 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002850 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2851 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2852 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2853 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002854 /* unmute pins for output (no gain on this amp) */
2855 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2856 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2857 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2858 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2859
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002861 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002862 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2863 /* Mic2 (as headphone out) for HP output */
2864 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002865 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002866 /* Line In pin widget for input */
2867 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2868 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2869 /* Line2 (as front mic) pin widget for input and vref at 80% */
2870 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2871 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2872 /* CD pin widget for input */
2873 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875 { }
2876};
2877
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002878/*
2879 * W810 pin configuration:
2880 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2881 */
2882static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 /* hphone/speaker input selector: front DAC */
2884 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2885
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002886 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2887 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2888 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2890 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2892
2893 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002894 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 { }
2897};
2898
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002899/*
2900 * Z71V pin configuration:
2901 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2902 */
2903static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002904 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002905 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002906 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002907 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002908
Takashi Iwai16ded522005-06-10 19:58:24 +02002909 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002910 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002911 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002912 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002913
2914 { }
2915};
2916
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002917/*
2918 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002919 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2920 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002921 */
2922static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2923 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2924
Takashi Iwai16ded522005-06-10 19:58:24 +02002925 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002926 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002927 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002928 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002929 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002930 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002931 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002932 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2933
Takashi Iwai16ded522005-06-10 19:58:24 +02002934 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002935 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002936 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002937 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002938 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002939 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002940 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002941 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002942 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002943
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002944 { }
2945};
Takashi Iwai16ded522005-06-10 19:58:24 +02002946
Kailang Yangccc656c2006-10-17 12:32:26 +02002947/*
2948 * Uniwill pin configuration:
2949 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2950 * line = 0x1a
2951 */
2952static struct hda_verb alc880_uniwill_init_verbs[] = {
2953 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2954
2955 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2956 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2957 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2958 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2959 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2960 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2961 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2962 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2963 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2964 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2965 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2966 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2967 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2968 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2969
2970 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2971 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2972 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2973 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2974 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2975 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2976 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2977 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2978 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2979
2980 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2981 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2982
2983 { }
2984};
2985
2986/*
2987* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002988* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002989 */
2990static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2991 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2992
2993 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2994 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2995 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2996 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2997 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2998 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2999 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3000 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3001 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3002 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3003 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3004 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3005
3006 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3007 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3008 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3009 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3010 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3011 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3012
3013 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3014 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3015
3016 { }
3017};
3018
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003019static struct hda_verb alc880_beep_init_verbs[] = {
3020 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3021 { }
3022};
3023
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003024/* auto-toggle front mic */
3025static void alc880_uniwill_mic_automute(struct hda_codec *codec)
3026{
3027 unsigned int present;
3028 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003029
Wu Fengguang864f92b2009-11-18 12:38:02 +08003030 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003031 bits = present ? HDA_AMP_MUTE : 0;
3032 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003033}
3034
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003035static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003036{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003037 struct alc_spec *spec = codec->spec;
3038
3039 spec->autocfg.hp_pins[0] = 0x14;
3040 spec->autocfg.speaker_pins[0] = 0x15;
3041 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003042}
3043
3044static void alc880_uniwill_init_hook(struct hda_codec *codec)
3045{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003046 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003047 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003048}
3049
3050static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3051 unsigned int res)
3052{
3053 /* Looks like the unsol event is incompatible with the standard
3054 * definition. 4bit tag is placed at 28 bit!
3055 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003056 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003057 case ALC880_MIC_EVENT:
3058 alc880_uniwill_mic_automute(codec);
3059 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003060 default:
3061 alc_automute_amp_unsol_event(codec, res);
3062 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003063 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003064}
3065
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003066static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003067{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003068 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003069
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003070 spec->autocfg.hp_pins[0] = 0x14;
3071 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003072}
3073
3074static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3075{
3076 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003077
Kailang Yangccc656c2006-10-17 12:32:26 +02003078 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003079 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3080 present &= HDA_AMP_VOLMASK;
3081 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3082 HDA_AMP_VOLMASK, present);
3083 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3084 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003085}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003086
Kailang Yangccc656c2006-10-17 12:32:26 +02003087static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3088 unsigned int res)
3089{
3090 /* Looks like the unsol event is incompatible with the standard
3091 * definition. 4bit tag is placed at 28 bit!
3092 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003093 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003094 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003095 else
3096 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003097}
3098
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003099/*
3100 * F1734 pin configuration:
3101 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3102 */
3103static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003104 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003105 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3106 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3107 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3108 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3109
3110 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3111 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3112 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3113 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3114
3115 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3116 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003117 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003118 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3119 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3120 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3121 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3122 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3123 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003124
Takashi Iwai937b4162008-02-11 14:52:36 +01003125 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3126 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3127
Takashi Iwai16ded522005-06-10 19:58:24 +02003128 { }
3129};
3130
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003131/*
3132 * ASUS pin configuration:
3133 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3134 */
3135static struct hda_verb alc880_pin_asus_init_verbs[] = {
3136 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3137 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3138 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3139 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3140
3141 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3142 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3143 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3144 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3145 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3146 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3147 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3148 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3149
3150 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3151 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3152 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3153 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3154 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3155 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3156 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3157 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3158 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003159
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003160 { }
3161};
3162
3163/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003164#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3165#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003166#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003167
Kailang Yangdf694da2005-12-05 19:42:22 +01003168/* Clevo m520g init */
3169static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3170 /* headphone output */
3171 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3172 /* line-out */
3173 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3174 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3175 /* Line-in */
3176 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3177 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3178 /* CD */
3179 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3180 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3181 /* Mic1 (rear panel) */
3182 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3183 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3184 /* Mic2 (front panel) */
3185 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3186 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3187 /* headphone */
3188 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3189 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3190 /* change to EAPD mode */
3191 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3192 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3193
3194 { }
3195};
3196
3197static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003198 /* change to EAPD mode */
3199 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3200 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3201
Kailang Yangdf694da2005-12-05 19:42:22 +01003202 /* Headphone output */
3203 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3204 /* Front output*/
3205 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3206 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3207
3208 /* Line In pin widget for input */
3209 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3210 /* CD pin widget for input */
3211 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3212 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3213 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3214
3215 /* change to EAPD mode */
3216 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3217 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3218
3219 { }
3220};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003221
3222/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003223 * LG m1 express dual
3224 *
3225 * Pin assignment:
3226 * Rear Line-In/Out (blue): 0x14
3227 * Build-in Mic-In: 0x15
3228 * Speaker-out: 0x17
3229 * HP-Out (green): 0x1b
3230 * Mic-In/Out (red): 0x19
3231 * SPDIF-Out: 0x1e
3232 */
3233
3234/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3235static hda_nid_t alc880_lg_dac_nids[3] = {
3236 0x05, 0x02, 0x03
3237};
3238
3239/* seems analog CD is not working */
3240static struct hda_input_mux alc880_lg_capture_source = {
3241 .num_items = 3,
3242 .items = {
3243 { "Mic", 0x1 },
3244 { "Line", 0x5 },
3245 { "Internal Mic", 0x6 },
3246 },
3247};
3248
3249/* 2,4,6 channel modes */
3250static struct hda_verb alc880_lg_ch2_init[] = {
3251 /* set line-in and mic-in to input */
3252 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3253 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3254 { }
3255};
3256
3257static struct hda_verb alc880_lg_ch4_init[] = {
3258 /* set line-in to out and mic-in to input */
3259 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3260 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3261 { }
3262};
3263
3264static struct hda_verb alc880_lg_ch6_init[] = {
3265 /* set line-in and mic-in to output */
3266 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3267 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3268 { }
3269};
3270
3271static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3272 { 2, alc880_lg_ch2_init },
3273 { 4, alc880_lg_ch4_init },
3274 { 6, alc880_lg_ch6_init },
3275};
3276
3277static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003278 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3279 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003280 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3281 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3282 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3283 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3284 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3285 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3286 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3287 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3288 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3289 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3290 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3291 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3292 {
3293 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3294 .name = "Channel Mode",
3295 .info = alc_ch_mode_info,
3296 .get = alc_ch_mode_get,
3297 .put = alc_ch_mode_put,
3298 },
3299 { } /* end */
3300};
3301
3302static struct hda_verb alc880_lg_init_verbs[] = {
3303 /* set capture source to mic-in */
3304 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3305 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3306 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3307 /* mute all amp mixer inputs */
3308 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003309 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3310 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003311 /* line-in to input */
3312 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3313 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3314 /* built-in mic */
3315 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3316 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3317 /* speaker-out */
3318 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3319 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3320 /* mic-in to input */
3321 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3322 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3323 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3324 /* HP-out */
3325 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3326 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3327 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3328 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003329 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003330 { }
3331};
3332
3333/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003334static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003335{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003336 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003337
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003338 spec->autocfg.hp_pins[0] = 0x1b;
3339 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003340}
3341
3342/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003343 * LG LW20
3344 *
3345 * Pin assignment:
3346 * Speaker-out: 0x14
3347 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003348 * Built-in Mic-In: 0x19
3349 * Line-In: 0x1b
3350 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003351 * SPDIF-Out: 0x1e
3352 */
3353
Takashi Iwaid6815182006-03-23 16:06:23 +01003354static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003355 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003356 .items = {
3357 { "Mic", 0x0 },
3358 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003359 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003360 },
3361};
3362
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003363#define alc880_lg_lw_modes alc880_threestack_modes
3364
Takashi Iwaid6815182006-03-23 16:06:23 +01003365static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003366 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3367 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3368 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3369 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3370 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3371 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3372 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3373 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3374 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3375 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003376 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3377 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3378 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3379 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003380 {
3381 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3382 .name = "Channel Mode",
3383 .info = alc_ch_mode_info,
3384 .get = alc_ch_mode_get,
3385 .put = alc_ch_mode_put,
3386 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003387 { } /* end */
3388};
3389
3390static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003391 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3392 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3393 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3394
Takashi Iwaid6815182006-03-23 16:06:23 +01003395 /* set capture source to mic-in */
3396 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3397 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3398 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003399 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003400 /* speaker-out */
3401 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3402 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3403 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003404 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3405 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3406 /* mic-in to input */
3407 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3408 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3409 /* built-in mic */
3410 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3411 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3412 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003413 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003414 { }
3415};
3416
3417/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003418static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003419{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003420 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003421
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003422 spec->autocfg.hp_pins[0] = 0x1b;
3423 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003424}
3425
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003426static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3427 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3428 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3429 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3430 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3431 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3432 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3433 { } /* end */
3434};
3435
3436static struct hda_input_mux alc880_medion_rim_capture_source = {
3437 .num_items = 2,
3438 .items = {
3439 { "Mic", 0x0 },
3440 { "Internal Mic", 0x1 },
3441 },
3442};
3443
3444static struct hda_verb alc880_medion_rim_init_verbs[] = {
3445 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3446
3447 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3448 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3449
3450 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3451 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3452 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3453 /* Mic2 (as headphone out) for HP output */
3454 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3455 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3456 /* Internal Speaker */
3457 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3458 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3459
3460 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3461 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3462
3463 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3464 { }
3465};
3466
3467/* toggle speaker-output according to the hp-jack state */
3468static void alc880_medion_rim_automute(struct hda_codec *codec)
3469{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003470 struct alc_spec *spec = codec->spec;
3471 alc_automute_amp(codec);
3472 /* toggle EAPD */
3473 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003474 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3475 else
3476 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3477}
3478
3479static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3480 unsigned int res)
3481{
3482 /* Looks like the unsol event is incompatible with the standard
3483 * definition. 4bit tag is placed at 28 bit!
3484 */
3485 if ((res >> 28) == ALC880_HP_EVENT)
3486 alc880_medion_rim_automute(codec);
3487}
3488
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003489static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003490{
3491 struct alc_spec *spec = codec->spec;
3492
3493 spec->autocfg.hp_pins[0] = 0x14;
3494 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003495}
3496
Takashi Iwaicb53c622007-08-10 17:21:45 +02003497#ifdef CONFIG_SND_HDA_POWER_SAVE
3498static struct hda_amp_list alc880_loopbacks[] = {
3499 { 0x0b, HDA_INPUT, 0 },
3500 { 0x0b, HDA_INPUT, 1 },
3501 { 0x0b, HDA_INPUT, 2 },
3502 { 0x0b, HDA_INPUT, 3 },
3503 { 0x0b, HDA_INPUT, 4 },
3504 { } /* end */
3505};
3506
3507static struct hda_amp_list alc880_lg_loopbacks[] = {
3508 { 0x0b, HDA_INPUT, 1 },
3509 { 0x0b, HDA_INPUT, 6 },
3510 { 0x0b, HDA_INPUT, 7 },
3511 { } /* end */
3512};
3513#endif
3514
Takashi Iwaid6815182006-03-23 16:06:23 +01003515/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003516 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003517 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003518
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519static int alc_init(struct hda_codec *codec)
3520{
3521 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003522 unsigned int i;
3523
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003524 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003525 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003526
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003527 for (i = 0; i < spec->num_init_verbs; i++)
3528 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003529
3530 if (spec->init_hook)
3531 spec->init_hook(codec);
3532
Takashi Iwaiad358792010-03-30 18:00:59 +02003533#ifdef CONFIG_SND_HDA_POWER_SAVE
3534 if (codec->patch_ops.check_power_status)
3535 codec->patch_ops.check_power_status(codec, 0x01);
3536#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 return 0;
3538}
3539
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003540static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3541{
3542 struct alc_spec *spec = codec->spec;
3543
3544 if (spec->unsol_event)
3545 spec->unsol_event(codec, res);
3546}
3547
Takashi Iwaicb53c622007-08-10 17:21:45 +02003548#ifdef CONFIG_SND_HDA_POWER_SAVE
3549static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3550{
3551 struct alc_spec *spec = codec->spec;
3552 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3553}
3554#endif
3555
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556/*
3557 * Analog playback callbacks
3558 */
3559static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3560 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003561 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562{
3563 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003564 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3565 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566}
3567
3568static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3569 struct hda_codec *codec,
3570 unsigned int stream_tag,
3571 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003572 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573{
3574 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003575 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3576 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577}
3578
3579static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3580 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003581 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582{
3583 struct alc_spec *spec = codec->spec;
3584 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3585}
3586
3587/*
3588 * Digital out
3589 */
3590static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3591 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003592 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593{
3594 struct alc_spec *spec = codec->spec;
3595 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3596}
3597
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003598static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3599 struct hda_codec *codec,
3600 unsigned int stream_tag,
3601 unsigned int format,
3602 struct snd_pcm_substream *substream)
3603{
3604 struct alc_spec *spec = codec->spec;
3605 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3606 stream_tag, format, substream);
3607}
3608
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003609static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3610 struct hda_codec *codec,
3611 struct snd_pcm_substream *substream)
3612{
3613 struct alc_spec *spec = codec->spec;
3614 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3615}
3616
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3618 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003619 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620{
3621 struct alc_spec *spec = codec->spec;
3622 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3623}
3624
3625/*
3626 * Analog capture
3627 */
Takashi Iwai63300792008-01-24 15:31:36 +01003628static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 struct hda_codec *codec,
3630 unsigned int stream_tag,
3631 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003632 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633{
3634 struct alc_spec *spec = codec->spec;
3635
Takashi Iwai63300792008-01-24 15:31:36 +01003636 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 stream_tag, 0, format);
3638 return 0;
3639}
3640
Takashi Iwai63300792008-01-24 15:31:36 +01003641static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003643 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644{
3645 struct alc_spec *spec = codec->spec;
3646
Takashi Iwai888afa12008-03-18 09:57:50 +01003647 snd_hda_codec_cleanup_stream(codec,
3648 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 return 0;
3650}
3651
Takashi Iwai840b64c2010-07-13 22:49:01 +02003652/* analog capture with dynamic dual-adc changes */
3653static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3654 struct hda_codec *codec,
3655 unsigned int stream_tag,
3656 unsigned int format,
3657 struct snd_pcm_substream *substream)
3658{
3659 struct alc_spec *spec = codec->spec;
3660 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
3661 spec->cur_adc_stream_tag = stream_tag;
3662 spec->cur_adc_format = format;
3663 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
3664 return 0;
3665}
3666
3667static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3668 struct hda_codec *codec,
3669 struct snd_pcm_substream *substream)
3670{
3671 struct alc_spec *spec = codec->spec;
3672 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3673 spec->cur_adc = 0;
3674 return 0;
3675}
3676
3677static struct hda_pcm_stream dualmic_pcm_analog_capture = {
3678 .substreams = 1,
3679 .channels_min = 2,
3680 .channels_max = 2,
3681 .nid = 0, /* fill later */
3682 .ops = {
3683 .prepare = dualmic_capture_pcm_prepare,
3684 .cleanup = dualmic_capture_pcm_cleanup
3685 },
3686};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687
3688/*
3689 */
3690static struct hda_pcm_stream alc880_pcm_analog_playback = {
3691 .substreams = 1,
3692 .channels_min = 2,
3693 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003694 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 .ops = {
3696 .open = alc880_playback_pcm_open,
3697 .prepare = alc880_playback_pcm_prepare,
3698 .cleanup = alc880_playback_pcm_cleanup
3699 },
3700};
3701
3702static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003703 .substreams = 1,
3704 .channels_min = 2,
3705 .channels_max = 2,
3706 /* NID is set in alc_build_pcms */
3707};
3708
3709static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3710 .substreams = 1,
3711 .channels_min = 2,
3712 .channels_max = 2,
3713 /* NID is set in alc_build_pcms */
3714};
3715
3716static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3717 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 .channels_min = 2,
3719 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003720 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003722 .prepare = alc880_alt_capture_pcm_prepare,
3723 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 },
3725};
3726
3727static struct hda_pcm_stream alc880_pcm_digital_playback = {
3728 .substreams = 1,
3729 .channels_min = 2,
3730 .channels_max = 2,
3731 /* NID is set in alc_build_pcms */
3732 .ops = {
3733 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003734 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003735 .prepare = alc880_dig_playback_pcm_prepare,
3736 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 },
3738};
3739
3740static struct hda_pcm_stream alc880_pcm_digital_capture = {
3741 .substreams = 1,
3742 .channels_min = 2,
3743 .channels_max = 2,
3744 /* NID is set in alc_build_pcms */
3745};
3746
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003747/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003748static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003749 .substreams = 0,
3750 .channels_min = 0,
3751 .channels_max = 0,
3752};
3753
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754static int alc_build_pcms(struct hda_codec *codec)
3755{
3756 struct alc_spec *spec = codec->spec;
3757 struct hda_pcm *info = spec->pcm_rec;
3758 int i;
3759
3760 codec->num_pcms = 1;
3761 codec->pcm_info = info;
3762
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003763 if (spec->no_analog)
3764 goto skip_analog;
3765
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003766 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3767 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003769
Takashi Iwai4a471b72005-12-07 13:56:29 +01003770 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003771 if (snd_BUG_ON(!spec->multiout.dac_nids))
3772 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003773 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3774 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3775 }
3776 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003777 if (snd_BUG_ON(!spec->adc_nids))
3778 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003779 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3780 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Takashi Iwai4a471b72005-12-07 13:56:29 +01003783 if (spec->channel_mode) {
3784 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3785 for (i = 0; i < spec->num_channel_mode; i++) {
3786 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3787 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 }
3790 }
3791
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003792 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003793 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003795 snprintf(spec->stream_name_digital,
3796 sizeof(spec->stream_name_digital),
3797 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003798 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003799 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003800 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003802 if (spec->dig_out_type)
3803 info->pcm_type = spec->dig_out_type;
3804 else
3805 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003806 if (spec->multiout.dig_out_nid &&
3807 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3809 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3810 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003811 if (spec->dig_in_nid &&
3812 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3814 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3815 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003816 /* FIXME: do we need this for all Realtek codec models? */
3817 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 }
3819
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003820 if (spec->no_analog)
3821 return 0;
3822
Takashi Iwaie08a0072006-09-07 17:52:14 +02003823 /* If the use of more than one ADC is requested for the current
3824 * model, configure a second analog capture-only PCM.
3825 */
3826 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003827 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3828 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003829 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003830 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003831 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003832 if (spec->alt_dac_nid) {
3833 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3834 *spec->stream_analog_alt_playback;
3835 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3836 spec->alt_dac_nid;
3837 } else {
3838 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3839 alc_pcm_null_stream;
3840 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3841 }
3842 if (spec->num_adc_nids > 1) {
3843 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3844 *spec->stream_analog_alt_capture;
3845 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3846 spec->adc_nids[1];
3847 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3848 spec->num_adc_nids - 1;
3849 } else {
3850 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3851 alc_pcm_null_stream;
3852 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003853 }
3854 }
3855
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 return 0;
3857}
3858
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003859static inline void alc_shutup(struct hda_codec *codec)
3860{
3861 snd_hda_shutup_pins(codec);
3862}
3863
Takashi Iwai603c4012008-07-30 15:01:44 +02003864static void alc_free_kctls(struct hda_codec *codec)
3865{
3866 struct alc_spec *spec = codec->spec;
3867
3868 if (spec->kctls.list) {
3869 struct snd_kcontrol_new *kctl = spec->kctls.list;
3870 int i;
3871 for (i = 0; i < spec->kctls.used; i++)
3872 kfree(kctl[i].name);
3873 }
3874 snd_array_free(&spec->kctls);
3875}
3876
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877static void alc_free(struct hda_codec *codec)
3878{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003879 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003880
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003881 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003882 return;
3883
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003884 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02003885 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003886 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003887 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888}
3889
Hector Martinf5de24b2009-12-20 22:51:31 +01003890#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05003891static void alc_power_eapd(struct hda_codec *codec)
3892{
3893 /* We currently only handle front, HP */
3894 switch (codec->vendor_id) {
3895 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003896 set_eapd(codec, 0x0f, 0);
3897 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05003898 break;
3899 case 0x10ec0262:
3900 case 0x10ec0267:
3901 case 0x10ec0268:
3902 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003903 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05003904 case 0x10ec0272:
3905 case 0x10ec0660:
3906 case 0x10ec0662:
3907 case 0x10ec0663:
3908 case 0x10ec0862:
3909 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003910 set_eapd(codec, 0x14, 0);
3911 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05003912 break;
3913 }
3914}
3915
Hector Martinf5de24b2009-12-20 22:51:31 +01003916static int alc_suspend(struct hda_codec *codec, pm_message_t state)
3917{
3918 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003919 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003920 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05003921 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003922 return 0;
3923}
3924#endif
3925
Takashi Iwaie044c392008-10-27 16:56:24 +01003926#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003927static int alc_resume(struct hda_codec *codec)
3928{
Takashi Iwaie044c392008-10-27 16:56:24 +01003929 codec->patch_ops.init(codec);
3930 snd_hda_codec_resume_amp(codec);
3931 snd_hda_codec_resume_cache(codec);
Takashi Iwaiad358792010-03-30 18:00:59 +02003932#ifdef CONFIG_SND_HDA_POWER_SAVE
3933 if (codec->patch_ops.check_power_status)
3934 codec->patch_ops.check_power_status(codec, 0x01);
3935#endif
Takashi Iwaie044c392008-10-27 16:56:24 +01003936 return 0;
3937}
Takashi Iwaie044c392008-10-27 16:56:24 +01003938#endif
3939
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940/*
3941 */
3942static struct hda_codec_ops alc_patch_ops = {
3943 .build_controls = alc_build_controls,
3944 .build_pcms = alc_build_pcms,
3945 .init = alc_init,
3946 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003947 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003948#ifdef SND_HDA_NEEDS_RESUME
3949 .resume = alc_resume,
3950#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003951#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01003952 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003953 .check_power_status = alc_check_power_status,
3954#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05003955 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956};
3957
Kailang Yangc027ddc2010-03-19 11:33:06 +01003958/* replace the codec chip_name with the given string */
3959static int alc_codec_rename(struct hda_codec *codec, const char *name)
3960{
3961 kfree(codec->chip_name);
3962 codec->chip_name = kstrdup(name, GFP_KERNEL);
3963 if (!codec->chip_name) {
3964 alc_free(codec);
3965 return -ENOMEM;
3966 }
3967 return 0;
3968}
3969
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003970/*
3971 * Test configuration for debugging
3972 *
3973 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3974 * enum controls.
3975 */
3976#ifdef CONFIG_SND_DEBUG
3977static hda_nid_t alc880_test_dac_nids[4] = {
3978 0x02, 0x03, 0x04, 0x05
3979};
3980
3981static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003982 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003983 .items = {
3984 { "In-1", 0x0 },
3985 { "In-2", 0x1 },
3986 { "In-3", 0x2 },
3987 { "In-4", 0x3 },
3988 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003989 { "Front", 0x5 },
3990 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003991 },
3992};
3993
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003994static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003995 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003996 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003997 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003998 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003999};
4000
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004001static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4002 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004003{
4004 static char *texts[] = {
4005 "N/A", "Line Out", "HP Out",
4006 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4007 };
4008 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4009 uinfo->count = 1;
4010 uinfo->value.enumerated.items = 8;
4011 if (uinfo->value.enumerated.item >= 8)
4012 uinfo->value.enumerated.item = 7;
4013 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4014 return 0;
4015}
4016
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004017static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4018 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004019{
4020 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4021 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4022 unsigned int pin_ctl, item = 0;
4023
4024 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4025 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4026 if (pin_ctl & AC_PINCTL_OUT_EN) {
4027 if (pin_ctl & AC_PINCTL_HP_EN)
4028 item = 2;
4029 else
4030 item = 1;
4031 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4032 switch (pin_ctl & AC_PINCTL_VREFEN) {
4033 case AC_PINCTL_VREF_HIZ: item = 3; break;
4034 case AC_PINCTL_VREF_50: item = 4; break;
4035 case AC_PINCTL_VREF_GRD: item = 5; break;
4036 case AC_PINCTL_VREF_80: item = 6; break;
4037 case AC_PINCTL_VREF_100: item = 7; break;
4038 }
4039 }
4040 ucontrol->value.enumerated.item[0] = item;
4041 return 0;
4042}
4043
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004044static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4045 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004046{
4047 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4048 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4049 static unsigned int ctls[] = {
4050 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4051 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4052 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4053 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4054 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4055 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4056 };
4057 unsigned int old_ctl, new_ctl;
4058
4059 old_ctl = snd_hda_codec_read(codec, nid, 0,
4060 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4061 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4062 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004063 int val;
4064 snd_hda_codec_write_cache(codec, nid, 0,
4065 AC_VERB_SET_PIN_WIDGET_CONTROL,
4066 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004067 val = ucontrol->value.enumerated.item[0] >= 3 ?
4068 HDA_AMP_MUTE : 0;
4069 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4070 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004071 return 1;
4072 }
4073 return 0;
4074}
4075
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004076static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4077 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004078{
4079 static char *texts[] = {
4080 "Front", "Surround", "CLFE", "Side"
4081 };
4082 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4083 uinfo->count = 1;
4084 uinfo->value.enumerated.items = 4;
4085 if (uinfo->value.enumerated.item >= 4)
4086 uinfo->value.enumerated.item = 3;
4087 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4088 return 0;
4089}
4090
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004091static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4092 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004093{
4094 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4095 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4096 unsigned int sel;
4097
4098 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4099 ucontrol->value.enumerated.item[0] = sel & 3;
4100 return 0;
4101}
4102
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004103static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4104 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004105{
4106 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4107 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4108 unsigned int sel;
4109
4110 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4111 if (ucontrol->value.enumerated.item[0] != sel) {
4112 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004113 snd_hda_codec_write_cache(codec, nid, 0,
4114 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004115 return 1;
4116 }
4117 return 0;
4118}
4119
4120#define PIN_CTL_TEST(xname,nid) { \
4121 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4122 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004123 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004124 .info = alc_test_pin_ctl_info, \
4125 .get = alc_test_pin_ctl_get, \
4126 .put = alc_test_pin_ctl_put, \
4127 .private_value = nid \
4128 }
4129
4130#define PIN_SRC_TEST(xname,nid) { \
4131 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4132 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004133 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004134 .info = alc_test_pin_src_info, \
4135 .get = alc_test_pin_src_get, \
4136 .put = alc_test_pin_src_put, \
4137 .private_value = nid \
4138 }
4139
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004140static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004141 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4142 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4143 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4144 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004145 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4146 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4147 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4148 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004149 PIN_CTL_TEST("Front Pin Mode", 0x14),
4150 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4151 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4152 PIN_CTL_TEST("Side Pin Mode", 0x17),
4153 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4154 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4155 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4156 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4157 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4158 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4159 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4160 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4161 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4162 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4163 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4164 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4165 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4166 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4167 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4168 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4169 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4170 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004171 {
4172 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4173 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004174 .info = alc_ch_mode_info,
4175 .get = alc_ch_mode_get,
4176 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004177 },
4178 { } /* end */
4179};
4180
4181static struct hda_verb alc880_test_init_verbs[] = {
4182 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004183 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4184 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4185 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4186 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4187 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4188 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4189 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4190 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004191 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004192 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4193 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4194 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4195 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004196 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004197 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4198 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4199 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4200 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004201 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004202 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4203 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4204 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4205 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004206 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004207 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4208 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004209 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4210 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4211 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004212 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004213 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4214 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4215 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4216 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004217 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004218 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004219 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004220 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004221 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004222 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004223 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004224 /* Analog input/passthru */
4225 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4226 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4227 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4228 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4229 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004230 { }
4231};
4232#endif
4233
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234/*
4235 */
4236
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004237static const char *alc880_models[ALC880_MODEL_LAST] = {
4238 [ALC880_3ST] = "3stack",
4239 [ALC880_TCL_S700] = "tcl",
4240 [ALC880_3ST_DIG] = "3stack-digout",
4241 [ALC880_CLEVO] = "clevo",
4242 [ALC880_5ST] = "5stack",
4243 [ALC880_5ST_DIG] = "5stack-digout",
4244 [ALC880_W810] = "w810",
4245 [ALC880_Z71V] = "z71v",
4246 [ALC880_6ST] = "6stack",
4247 [ALC880_6ST_DIG] = "6stack-digout",
4248 [ALC880_ASUS] = "asus",
4249 [ALC880_ASUS_W1V] = "asus-w1v",
4250 [ALC880_ASUS_DIG] = "asus-dig",
4251 [ALC880_ASUS_DIG2] = "asus-dig2",
4252 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004253 [ALC880_UNIWILL_P53] = "uniwill-p53",
4254 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004255 [ALC880_F1734] = "F1734",
4256 [ALC880_LG] = "lg",
4257 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004258 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004259#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004260 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004261#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004262 [ALC880_AUTO] = "auto",
4263};
4264
4265static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004266 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004267 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4268 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4269 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4270 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4271 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4272 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4273 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4274 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004275 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4276 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004277 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4278 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4279 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4280 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4281 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4282 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4283 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4284 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4285 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4286 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004287 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004288 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4289 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4290 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004291 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004292 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004293 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4294 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004295 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4296 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004297 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4298 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4299 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4300 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004301 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4302 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004303 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004304 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004305 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004306 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004307 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4308 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004309 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004310 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004311 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004312 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004313 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004314 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004315 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004316 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004317 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004318 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4319 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004320 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004321 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4322 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4323 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4324 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004325 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4326 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004327 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004328 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004329 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4330 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004331 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4332 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4333 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004334 /* default Intel */
4335 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004336 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4337 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 {}
4339};
4340
Takashi Iwai16ded522005-06-10 19:58:24 +02004341/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004342 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004343 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004344static struct alc_config_preset alc880_presets[] = {
4345 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004346 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004347 .init_verbs = { alc880_volume_init_verbs,
4348 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004349 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004350 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004351 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4352 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004353 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004354 .input_mux = &alc880_capture_source,
4355 },
4356 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004357 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004358 .init_verbs = { alc880_volume_init_verbs,
4359 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004360 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004361 .dac_nids = alc880_dac_nids,
4362 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004363 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4364 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004365 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004366 .input_mux = &alc880_capture_source,
4367 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004368 [ALC880_TCL_S700] = {
4369 .mixers = { alc880_tcl_s700_mixer },
4370 .init_verbs = { alc880_volume_init_verbs,
4371 alc880_pin_tcl_S700_init_verbs,
4372 alc880_gpio2_init_verbs },
4373 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4374 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004375 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4376 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004377 .hp_nid = 0x03,
4378 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4379 .channel_mode = alc880_2_jack_modes,
4380 .input_mux = &alc880_capture_source,
4381 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004382 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004383 .mixers = { alc880_three_stack_mixer,
4384 alc880_five_stack_mixer},
4385 .init_verbs = { alc880_volume_init_verbs,
4386 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004387 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4388 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004389 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4390 .channel_mode = alc880_fivestack_modes,
4391 .input_mux = &alc880_capture_source,
4392 },
4393 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004394 .mixers = { alc880_three_stack_mixer,
4395 alc880_five_stack_mixer },
4396 .init_verbs = { alc880_volume_init_verbs,
4397 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004398 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4399 .dac_nids = alc880_dac_nids,
4400 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004401 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4402 .channel_mode = alc880_fivestack_modes,
4403 .input_mux = &alc880_capture_source,
4404 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004405 [ALC880_6ST] = {
4406 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004407 .init_verbs = { alc880_volume_init_verbs,
4408 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004409 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4410 .dac_nids = alc880_6st_dac_nids,
4411 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4412 .channel_mode = alc880_sixstack_modes,
4413 .input_mux = &alc880_6stack_capture_source,
4414 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004415 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004416 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004417 .init_verbs = { alc880_volume_init_verbs,
4418 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004419 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4420 .dac_nids = alc880_6st_dac_nids,
4421 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004422 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4423 .channel_mode = alc880_sixstack_modes,
4424 .input_mux = &alc880_6stack_capture_source,
4425 },
4426 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004427 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004428 .init_verbs = { alc880_volume_init_verbs,
4429 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004430 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004431 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4432 .dac_nids = alc880_w810_dac_nids,
4433 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004434 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4435 .channel_mode = alc880_w810_modes,
4436 .input_mux = &alc880_capture_source,
4437 },
4438 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004439 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004440 .init_verbs = { alc880_volume_init_verbs,
4441 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004442 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4443 .dac_nids = alc880_z71v_dac_nids,
4444 .dig_out_nid = ALC880_DIGOUT_NID,
4445 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004446 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4447 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004448 .input_mux = &alc880_capture_source,
4449 },
4450 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004451 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004452 .init_verbs = { alc880_volume_init_verbs,
4453 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004454 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4455 .dac_nids = alc880_f1734_dac_nids,
4456 .hp_nid = 0x02,
4457 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4458 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004459 .input_mux = &alc880_f1734_capture_source,
4460 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004461 .setup = alc880_uniwill_p53_setup,
4462 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004463 },
4464 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004465 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004466 .init_verbs = { alc880_volume_init_verbs,
4467 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004468 alc880_gpio1_init_verbs },
4469 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4470 .dac_nids = alc880_asus_dac_nids,
4471 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4472 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004473 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004474 .input_mux = &alc880_capture_source,
4475 },
4476 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004477 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004478 .init_verbs = { alc880_volume_init_verbs,
4479 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004480 alc880_gpio1_init_verbs },
4481 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4482 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004483 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004484 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4485 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004486 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004487 .input_mux = &alc880_capture_source,
4488 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004489 [ALC880_ASUS_DIG2] = {
4490 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004491 .init_verbs = { alc880_volume_init_verbs,
4492 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004493 alc880_gpio2_init_verbs }, /* use GPIO2 */
4494 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4495 .dac_nids = alc880_asus_dac_nids,
4496 .dig_out_nid = ALC880_DIGOUT_NID,
4497 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4498 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004499 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004500 .input_mux = &alc880_capture_source,
4501 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004502 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004503 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004504 .init_verbs = { alc880_volume_init_verbs,
4505 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004506 alc880_gpio1_init_verbs },
4507 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4508 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004509 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004510 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4511 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004512 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004513 .input_mux = &alc880_capture_source,
4514 },
4515 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004516 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004517 .init_verbs = { alc880_volume_init_verbs,
4518 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004519 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4520 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004521 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004522 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4523 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004524 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004525 .input_mux = &alc880_capture_source,
4526 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004527 [ALC880_UNIWILL] = {
4528 .mixers = { alc880_uniwill_mixer },
4529 .init_verbs = { alc880_volume_init_verbs,
4530 alc880_uniwill_init_verbs },
4531 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4532 .dac_nids = alc880_asus_dac_nids,
4533 .dig_out_nid = ALC880_DIGOUT_NID,
4534 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4535 .channel_mode = alc880_threestack_modes,
4536 .need_dac_fix = 1,
4537 .input_mux = &alc880_capture_source,
4538 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004539 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004540 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004541 },
4542 [ALC880_UNIWILL_P53] = {
4543 .mixers = { alc880_uniwill_p53_mixer },
4544 .init_verbs = { alc880_volume_init_verbs,
4545 alc880_uniwill_p53_init_verbs },
4546 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4547 .dac_nids = alc880_asus_dac_nids,
4548 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004549 .channel_mode = alc880_threestack_modes,
4550 .input_mux = &alc880_capture_source,
4551 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004552 .setup = alc880_uniwill_p53_setup,
4553 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004554 },
4555 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004556 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004557 .init_verbs = { alc880_volume_init_verbs,
4558 alc880_uniwill_p53_init_verbs,
4559 alc880_beep_init_verbs },
4560 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4561 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004562 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004563 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4564 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004565 .input_mux = &alc880_capture_source,
4566 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004567 .setup = alc880_uniwill_p53_setup,
4568 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004569 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004570 [ALC880_CLEVO] = {
4571 .mixers = { alc880_three_stack_mixer },
4572 .init_verbs = { alc880_volume_init_verbs,
4573 alc880_pin_clevo_init_verbs },
4574 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4575 .dac_nids = alc880_dac_nids,
4576 .hp_nid = 0x03,
4577 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4578 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004579 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004580 .input_mux = &alc880_capture_source,
4581 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004582 [ALC880_LG] = {
4583 .mixers = { alc880_lg_mixer },
4584 .init_verbs = { alc880_volume_init_verbs,
4585 alc880_lg_init_verbs },
4586 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4587 .dac_nids = alc880_lg_dac_nids,
4588 .dig_out_nid = ALC880_DIGOUT_NID,
4589 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4590 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004591 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004592 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004593 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004594 .setup = alc880_lg_setup,
4595 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004596#ifdef CONFIG_SND_HDA_POWER_SAVE
4597 .loopbacks = alc880_lg_loopbacks,
4598#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004599 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004600 [ALC880_LG_LW] = {
4601 .mixers = { alc880_lg_lw_mixer },
4602 .init_verbs = { alc880_volume_init_verbs,
4603 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004604 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004605 .dac_nids = alc880_dac_nids,
4606 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004607 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4608 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004609 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004610 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004611 .setup = alc880_lg_lw_setup,
4612 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004613 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004614 [ALC880_MEDION_RIM] = {
4615 .mixers = { alc880_medion_rim_mixer },
4616 .init_verbs = { alc880_volume_init_verbs,
4617 alc880_medion_rim_init_verbs,
4618 alc_gpio2_init_verbs },
4619 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4620 .dac_nids = alc880_dac_nids,
4621 .dig_out_nid = ALC880_DIGOUT_NID,
4622 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4623 .channel_mode = alc880_2_jack_modes,
4624 .input_mux = &alc880_medion_rim_capture_source,
4625 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004626 .setup = alc880_medion_rim_setup,
4627 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004628 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004629#ifdef CONFIG_SND_DEBUG
4630 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004631 .mixers = { alc880_test_mixer },
4632 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004633 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4634 .dac_nids = alc880_test_dac_nids,
4635 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004636 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4637 .channel_mode = alc880_test_modes,
4638 .input_mux = &alc880_test_capture_source,
4639 },
4640#endif
4641};
4642
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004643/*
4644 * Automatic parse of I/O pins from the BIOS configuration
4645 */
4646
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004647enum {
4648 ALC_CTL_WIDGET_VOL,
4649 ALC_CTL_WIDGET_MUTE,
4650 ALC_CTL_BIND_MUTE,
4651};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004652static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004653 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4654 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004655 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004656};
4657
4658/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004659static int add_control(struct alc_spec *spec, int type, const char *name,
4660 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004661{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004662 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004663
Takashi Iwai603c4012008-07-30 15:01:44 +02004664 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4665 knew = snd_array_new(&spec->kctls);
4666 if (!knew)
4667 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004668 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004669 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004670 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004671 return -ENOMEM;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004672 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004673 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004674 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004675 return 0;
4676}
4677
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004678static int add_control_with_pfx(struct alc_spec *spec, int type,
4679 const char *pfx, const char *dir,
4680 const char *sfx, unsigned long val)
4681{
4682 char name[32];
4683 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
4684 return add_control(spec, type, name, val);
4685}
4686
4687#define add_pb_vol_ctrl(spec, type, pfx, val) \
4688 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
4689#define add_pb_sw_ctrl(spec, type, pfx, val) \
4690 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
4691
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004692#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4693#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4694#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4695#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004696#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4697#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4698#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4699#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4700#define ALC880_PIN_CD_NID 0x1c
4701
4702/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004703static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4704 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004705{
4706 hda_nid_t nid;
4707 int assigned[4];
4708 int i, j;
4709
4710 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004711 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004712
4713 /* check the pins hardwired to audio widget */
4714 for (i = 0; i < cfg->line_outs; i++) {
4715 nid = cfg->line_out_pins[i];
4716 if (alc880_is_fixed_pin(nid)) {
4717 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004718 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004719 assigned[idx] = 1;
4720 }
4721 }
4722 /* left pins can be connect to any audio widget */
4723 for (i = 0; i < cfg->line_outs; i++) {
4724 nid = cfg->line_out_pins[i];
4725 if (alc880_is_fixed_pin(nid))
4726 continue;
4727 /* search for an empty channel */
4728 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004729 if (!assigned[j]) {
4730 spec->multiout.dac_nids[i] =
4731 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004732 assigned[j] = 1;
4733 break;
4734 }
4735 }
4736 }
4737 spec->multiout.num_dacs = cfg->line_outs;
4738 return 0;
4739}
4740
4741/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004742static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4743 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004744{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004745 static const char *chname[4] = {
4746 "Front", "Surround", NULL /*CLFE*/, "Side"
4747 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004748 hda_nid_t nid;
4749 int i, err;
4750
4751 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004752 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004753 continue;
4754 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4755 if (i == 2) {
4756 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004757 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4758 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004759 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4760 HDA_OUTPUT));
4761 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004762 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004763 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4764 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004765 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4766 HDA_OUTPUT));
4767 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004768 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004769 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4770 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004771 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4772 HDA_INPUT));
4773 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004774 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004775 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4776 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004777 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4778 HDA_INPUT));
4779 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004780 return err;
4781 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004782 const char *pfx;
4783 if (cfg->line_outs == 1 &&
4784 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4785 pfx = "Speaker";
4786 else
4787 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004788 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004789 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4790 HDA_OUTPUT));
4791 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004792 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004793 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004794 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4795 HDA_INPUT));
4796 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004797 return err;
4798 }
4799 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004800 return 0;
4801}
4802
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004803/* add playback controls for speaker and HP outputs */
4804static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4805 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004806{
4807 hda_nid_t nid;
4808 int err;
4809
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004810 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004811 return 0;
4812
4813 if (alc880_is_fixed_pin(pin)) {
4814 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004815 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004816 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004817 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004818 else
4819 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004820 /* control HP volume/switch on the output mixer amp */
4821 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004822 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004823 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4824 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004825 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004826 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004827 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4828 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004829 return err;
4830 } else if (alc880_is_multi_pin(pin)) {
4831 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004832 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004833 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004834 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4835 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004836 return err;
4837 }
4838 return 0;
4839}
4840
4841/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004842static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4843 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004844 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004845{
Kailang Yangdf694da2005-12-05 19:42:22 +01004846 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004847
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004848 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004849 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4850 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004851 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004852 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004853 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4854 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004855 return err;
4856 return 0;
4857}
4858
Takashi Iwai05f5f472009-08-25 13:10:18 +02004859static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004860{
Takashi Iwai05f5f472009-08-25 13:10:18 +02004861 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
4862 return (pincap & AC_PINCAP_IN) != 0;
4863}
4864
4865/* create playback/capture controls for input pins */
4866static int alc_auto_create_input_ctls(struct hda_codec *codec,
4867 const struct auto_pin_cfg *cfg,
4868 hda_nid_t mixer,
4869 hda_nid_t cap1, hda_nid_t cap2)
4870{
4871 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004872 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004873 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004874
4875 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02004876 hda_nid_t pin;
4877
4878 pin = cfg->input_pins[i];
4879 if (!alc_is_input_pin(codec, pin))
4880 continue;
4881
4882 if (mixer) {
4883 idx = get_connection_index(codec, mixer, pin);
4884 if (idx >= 0) {
4885 err = new_analog_input(spec, pin,
4886 auto_pin_cfg_labels[i],
4887 idx, mixer);
4888 if (err < 0)
4889 return err;
4890 }
4891 }
4892
4893 if (!cap1)
4894 continue;
4895 idx = get_connection_index(codec, cap1, pin);
4896 if (idx < 0 && cap2)
4897 idx = get_connection_index(codec, cap2, pin);
4898 if (idx >= 0) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004899 imux->items[imux->num_items].label =
4900 auto_pin_cfg_labels[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004901 imux->items[imux->num_items].index = idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004902 imux->num_items++;
4903 }
4904 }
4905 return 0;
4906}
4907
Takashi Iwai05f5f472009-08-25 13:10:18 +02004908static int alc880_auto_create_input_ctls(struct hda_codec *codec,
4909 const struct auto_pin_cfg *cfg)
4910{
4911 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
4912}
4913
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004914static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4915 unsigned int pin_type)
4916{
4917 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4918 pin_type);
4919 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004920 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4921 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004922}
4923
Kailang Yangdf694da2005-12-05 19:42:22 +01004924static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4925 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004926 int dac_idx)
4927{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004928 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004929 /* need the manual connection? */
4930 if (alc880_is_multi_pin(nid)) {
4931 struct alc_spec *spec = codec->spec;
4932 int idx = alc880_multi_pin_idx(nid);
4933 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4934 AC_VERB_SET_CONNECT_SEL,
4935 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4936 }
4937}
4938
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004939static int get_pin_type(int line_out_type)
4940{
4941 if (line_out_type == AUTO_PIN_HP_OUT)
4942 return PIN_HP;
4943 else
4944 return PIN_OUT;
4945}
4946
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004947static void alc880_auto_init_multi_out(struct hda_codec *codec)
4948{
4949 struct alc_spec *spec = codec->spec;
4950 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004951
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004952 for (i = 0; i < spec->autocfg.line_outs; i++) {
4953 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004954 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4955 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004956 }
4957}
4958
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004959static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004960{
4961 struct alc_spec *spec = codec->spec;
4962 hda_nid_t pin;
4963
Takashi Iwai82bc9552006-03-21 11:24:42 +01004964 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004965 if (pin) /* connect to front */
4966 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004967 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004968 if (pin) /* connect to front */
4969 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4970}
4971
4972static void alc880_auto_init_analog_input(struct hda_codec *codec)
4973{
4974 struct alc_spec *spec = codec->spec;
4975 int i;
4976
4977 for (i = 0; i < AUTO_PIN_LAST; i++) {
4978 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004979 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004980 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004981 if (nid != ALC880_PIN_CD_NID &&
4982 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004983 snd_hda_codec_write(codec, nid, 0,
4984 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004985 AMP_OUT_MUTE);
4986 }
4987 }
4988}
4989
Takashi Iwai7f311a42010-04-09 17:32:23 +02004990static void alc880_auto_init_input_src(struct hda_codec *codec)
4991{
4992 struct alc_spec *spec = codec->spec;
4993 int c;
4994
4995 for (c = 0; c < spec->num_adc_nids; c++) {
4996 unsigned int mux_idx;
4997 const struct hda_input_mux *imux;
4998 mux_idx = c >= spec->num_mux_defs ? 0 : c;
4999 imux = &spec->input_mux[mux_idx];
5000 if (!imux->num_items && mux_idx > 0)
5001 imux = &spec->input_mux[0];
5002 if (imux)
5003 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5004 AC_VERB_SET_CONNECT_SEL,
5005 imux->items[0].index);
5006 }
5007}
5008
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005009/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005010/* return 1 if successful, 0 if the proper config is not found,
5011 * or a negative error code
5012 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005013static int alc880_parse_auto_config(struct hda_codec *codec)
5014{
5015 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01005016 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005017 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005018
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005019 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5020 alc880_ignore);
5021 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005022 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005023 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005024 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005025
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005026 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5027 if (err < 0)
5028 return err;
5029 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5030 if (err < 0)
5031 return err;
5032 err = alc880_auto_create_extra_out(spec,
5033 spec->autocfg.speaker_pins[0],
5034 "Speaker");
5035 if (err < 0)
5036 return err;
5037 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5038 "Headphone");
5039 if (err < 0)
5040 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005041 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005042 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005043 return err;
5044
5045 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5046
Takashi Iwai6a05ac42009-02-13 11:19:09 +01005047 /* check multiple SPDIF-out (for recent codecs) */
5048 for (i = 0; i < spec->autocfg.dig_outs; i++) {
5049 hda_nid_t dig_nid;
5050 err = snd_hda_get_connections(codec,
5051 spec->autocfg.dig_out_pins[i],
5052 &dig_nid, 1);
5053 if (err < 0)
5054 continue;
5055 if (!i)
5056 spec->multiout.dig_out_nid = dig_nid;
5057 else {
5058 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +01005059 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai6a05ac42009-02-13 11:19:09 +01005060 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +01005061 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01005062 }
5063 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005064 if (spec->autocfg.dig_in_pin)
5065 spec->dig_in_nid = ALC880_DIGIN_NID;
5066
Takashi Iwai603c4012008-07-30 15:01:44 +02005067 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005068 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005069
Takashi Iwaid88897e2008-10-31 15:01:37 +01005070 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005071
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005072 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005073 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005074
Kailang Yang6227cdc2010-02-25 08:36:52 +01005075 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005076
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005077 return 1;
5078}
5079
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005080/* additional initialization for auto-configuration model */
5081static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005082{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005083 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005084 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005085 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005086 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005087 alc880_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005088 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005089 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005090}
5091
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005092/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5093 * one of two digital mic pins, e.g. on ALC272
5094 */
5095static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005096{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005097 struct alc_spec *spec = codec->spec;
5098 int i;
5099
5100 for (i = 0; i < spec->num_adc_nids; i++) {
5101 hda_nid_t cap = spec->capsrc_nids ?
5102 spec->capsrc_nids[i] : spec->adc_nids[i];
5103 int iidx, eidx;
5104
5105 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5106 if (iidx < 0)
5107 continue;
5108 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5109 if (eidx < 0)
5110 continue;
5111 spec->int_mic.mux_idx = iidx;
5112 spec->ext_mic.mux_idx = eidx;
5113 if (spec->capsrc_nids)
5114 spec->capsrc_nids += i;
5115 spec->adc_nids += i;
5116 spec->num_adc_nids = 1;
5117 return;
5118 }
5119 snd_printd(KERN_INFO "hda_codec: %s: "
5120 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5121 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5122 spec->auto_mic = 0; /* disable auto-mic to be sure */
5123}
5124
Takashi Iwai840b64c2010-07-13 22:49:01 +02005125/* set the default connection to that pin */
5126static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5127{
5128 struct alc_spec *spec = codec->spec;
5129 int i;
5130
5131 for (i = 0; i < spec->num_adc_nids; i++) {
5132 hda_nid_t cap = spec->capsrc_nids ?
5133 spec->capsrc_nids[i] : spec->adc_nids[i];
5134 int idx;
5135
5136 idx = get_connection_index(codec, cap, pin);
5137 if (idx < 0)
5138 continue;
5139 /* select or unmute this route */
5140 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5141 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5142 HDA_AMP_MUTE, 0);
5143 } else {
5144 snd_hda_codec_write_cache(codec, cap, 0,
5145 AC_VERB_SET_CONNECT_SEL, idx);
5146 }
5147 return i; /* return the found index */
5148 }
5149 return -1; /* not found */
5150}
5151
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005152/* choose the ADC/MUX containing the input pin and initialize the setup */
5153static void fixup_single_adc(struct hda_codec *codec)
5154{
5155 struct alc_spec *spec = codec->spec;
Frederik Deweerdtd2db09b2010-03-05 16:34:31 +01005156 hda_nid_t pin = 0;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005157 int i;
5158
5159 /* search for the input pin; there must be only one */
5160 for (i = 0; i < AUTO_PIN_LAST; i++) {
5161 if (spec->autocfg.input_pins[i]) {
5162 pin = spec->autocfg.input_pins[i];
5163 break;
5164 }
5165 }
5166 if (!pin)
5167 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005168 i = init_capsrc_for_pin(codec, pin);
5169 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005170 /* use only this ADC */
5171 if (spec->capsrc_nids)
5172 spec->capsrc_nids += i;
5173 spec->adc_nids += i;
5174 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005175 }
5176}
5177
Takashi Iwai840b64c2010-07-13 22:49:01 +02005178/* initialize dual adcs */
5179static void fixup_dual_adc_switch(struct hda_codec *codec)
5180{
5181 struct alc_spec *spec = codec->spec;
5182 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5183 init_capsrc_for_pin(codec, spec->int_mic.pin);
5184}
5185
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005186static void set_capture_mixer(struct hda_codec *codec)
5187{
5188 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005189 static struct snd_kcontrol_new *caps[2][3] = {
5190 { alc_capture_mixer_nosrc1,
5191 alc_capture_mixer_nosrc2,
5192 alc_capture_mixer_nosrc3 },
5193 { alc_capture_mixer1,
5194 alc_capture_mixer2,
5195 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005196 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005197 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005198 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005199 int num_adcs = spec->num_adc_nids;
5200 if (spec->dual_adc_switch)
5201 fixup_dual_adc_switch(codec);
5202 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005203 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005204 else if (spec->input_mux) {
5205 if (spec->input_mux->num_items > 1)
5206 mux = 1;
5207 else if (spec->input_mux->num_items == 1)
5208 fixup_single_adc(codec);
5209 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005210 if (spec->dual_adc_switch)
5211 num_adcs = 1;
5212 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005213 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005214}
5215
Takashi Iwai66946352010-03-29 17:21:45 +02005216/* fill adc_nids (and capsrc_nids) containing all active input pins */
5217static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5218 int num_nids)
5219{
5220 struct alc_spec *spec = codec->spec;
5221 int n;
5222 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5223
5224 for (n = 0; n < num_nids; n++) {
5225 hda_nid_t adc, cap;
5226 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5227 int nconns, i, j;
5228
5229 adc = nids[n];
5230 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5231 continue;
5232 cap = adc;
5233 nconns = snd_hda_get_connections(codec, cap, conn,
5234 ARRAY_SIZE(conn));
5235 if (nconns == 1) {
5236 cap = conn[0];
5237 nconns = snd_hda_get_connections(codec, cap, conn,
5238 ARRAY_SIZE(conn));
5239 }
5240 if (nconns <= 0)
5241 continue;
5242 if (!fallback_adc) {
5243 fallback_adc = adc;
5244 fallback_cap = cap;
5245 }
5246 for (i = 0; i < AUTO_PIN_LAST; i++) {
5247 hda_nid_t nid = spec->autocfg.input_pins[i];
5248 if (!nid)
5249 continue;
5250 for (j = 0; j < nconns; j++) {
5251 if (conn[j] == nid)
5252 break;
5253 }
5254 if (j >= nconns)
5255 break;
5256 }
5257 if (i >= AUTO_PIN_LAST) {
5258 int num_adcs = spec->num_adc_nids;
5259 spec->private_adc_nids[num_adcs] = adc;
5260 spec->private_capsrc_nids[num_adcs] = cap;
5261 spec->num_adc_nids++;
5262 spec->adc_nids = spec->private_adc_nids;
5263 if (adc != cap)
5264 spec->capsrc_nids = spec->private_capsrc_nids;
5265 }
5266 }
5267 if (!spec->num_adc_nids) {
5268 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005269 " using fallback 0x%x\n",
5270 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005271 spec->private_adc_nids[0] = fallback_adc;
5272 spec->adc_nids = spec->private_adc_nids;
5273 if (fallback_adc != fallback_cap) {
5274 spec->private_capsrc_nids[0] = fallback_cap;
5275 spec->capsrc_nids = spec->private_adc_nids;
5276 }
5277 }
5278}
5279
Takashi Iwai67d634c2009-11-16 15:35:59 +01005280#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005281#define set_beep_amp(spec, nid, idx, dir) \
5282 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwai67d634c2009-11-16 15:35:59 +01005283#else
5284#define set_beep_amp(spec, nid, idx, dir) /* NOP */
5285#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005286
5287/*
5288 * OK, here we have finally the patch for ALC880
5289 */
5290
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291static int patch_alc880(struct hda_codec *codec)
5292{
5293 struct alc_spec *spec;
5294 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005295 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005297 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 if (spec == NULL)
5299 return -ENOMEM;
5300
5301 codec->spec = spec;
5302
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005303 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5304 alc880_models,
5305 alc880_cfg_tbl);
5306 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005307 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5308 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005309 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 }
5311
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005312 if (board_config == ALC880_AUTO) {
5313 /* automatic parse from the BIOS config */
5314 err = alc880_parse_auto_config(codec);
5315 if (err < 0) {
5316 alc_free(codec);
5317 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005318 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005319 printk(KERN_INFO
5320 "hda_codec: Cannot set up configuration "
5321 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005322 board_config = ALC880_3ST;
5323 }
5324 }
5325
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005326 err = snd_hda_attach_beep_device(codec, 0x1);
5327 if (err < 0) {
5328 alc_free(codec);
5329 return err;
5330 }
5331
Kailang Yangdf694da2005-12-05 19:42:22 +01005332 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005333 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5336 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005337 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5340 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5341
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005342 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005343 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005344 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005345 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005346 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005347 if (wcap != AC_WID_AUD_IN) {
5348 spec->adc_nids = alc880_adc_nids_alt;
5349 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005350 } else {
5351 spec->adc_nids = alc880_adc_nids;
5352 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005353 }
5354 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005355 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005356 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357
Takashi Iwai2134ea42008-01-10 16:53:55 +01005358 spec->vmaster_nid = 0x0c;
5359
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005361 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005362 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005363#ifdef CONFIG_SND_HDA_POWER_SAVE
5364 if (!spec->loopback.amplist)
5365 spec->loopback.amplist = alc880_loopbacks;
5366#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367
5368 return 0;
5369}
5370
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005371
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372/*
5373 * ALC260 support
5374 */
5375
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005376static hda_nid_t alc260_dac_nids[1] = {
5377 /* front */
5378 0x02,
5379};
5380
5381static hda_nid_t alc260_adc_nids[1] = {
5382 /* ADC0 */
5383 0x04,
5384};
5385
Kailang Yangdf694da2005-12-05 19:42:22 +01005386static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005387 /* ADC1 */
5388 0x05,
5389};
5390
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005391/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5392 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5393 */
5394static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005395 /* ADC0, ADC1 */
5396 0x04, 0x05
5397};
5398
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005399#define ALC260_DIGOUT_NID 0x03
5400#define ALC260_DIGIN_NID 0x06
5401
5402static struct hda_input_mux alc260_capture_source = {
5403 .num_items = 4,
5404 .items = {
5405 { "Mic", 0x0 },
5406 { "Front Mic", 0x1 },
5407 { "Line", 0x2 },
5408 { "CD", 0x4 },
5409 },
5410};
5411
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005412/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005413 * headphone jack and the internal CD lines since these are the only pins at
5414 * which audio can appear. For flexibility, also allow the option of
5415 * recording the mixer output on the second ADC (ADC0 doesn't have a
5416 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005417 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005418static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5419 {
5420 .num_items = 3,
5421 .items = {
5422 { "Mic/Line", 0x0 },
5423 { "CD", 0x4 },
5424 { "Headphone", 0x2 },
5425 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005426 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005427 {
5428 .num_items = 4,
5429 .items = {
5430 { "Mic/Line", 0x0 },
5431 { "CD", 0x4 },
5432 { "Headphone", 0x2 },
5433 { "Mixer", 0x5 },
5434 },
5435 },
5436
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005437};
5438
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005439/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5440 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005441 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005442static struct hda_input_mux alc260_acer_capture_sources[2] = {
5443 {
5444 .num_items = 4,
5445 .items = {
5446 { "Mic", 0x0 },
5447 { "Line", 0x2 },
5448 { "CD", 0x4 },
5449 { "Headphone", 0x5 },
5450 },
5451 },
5452 {
5453 .num_items = 5,
5454 .items = {
5455 { "Mic", 0x0 },
5456 { "Line", 0x2 },
5457 { "CD", 0x4 },
5458 { "Headphone", 0x6 },
5459 { "Mixer", 0x5 },
5460 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005461 },
5462};
Michael Schwingencc959482009-02-22 18:58:45 +01005463
5464/* Maxdata Favorit 100XS */
5465static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5466 {
5467 .num_items = 2,
5468 .items = {
5469 { "Line/Mic", 0x0 },
5470 { "CD", 0x4 },
5471 },
5472 },
5473 {
5474 .num_items = 3,
5475 .items = {
5476 { "Line/Mic", 0x0 },
5477 { "CD", 0x4 },
5478 { "Mixer", 0x5 },
5479 },
5480 },
5481};
5482
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483/*
5484 * This is just place-holder, so there's something for alc_build_pcms to look
5485 * at when it calculates the maximum number of channels. ALC260 has no mixer
5486 * element which allows changing the channel mode, so the verb list is
5487 * never used.
5488 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005489static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 { 2, NULL },
5491};
5492
Kailang Yangdf694da2005-12-05 19:42:22 +01005493
5494/* Mixer combinations
5495 *
5496 * basic: base_output + input + pc_beep + capture
5497 * HP: base_output + input + capture_alt
5498 * HP_3013: hp_3013 + input + capture
5499 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005500 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005501 */
5502
5503static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005504 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005505 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005506 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5507 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5508 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5509 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5510 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005511};
Kailang Yangdf694da2005-12-05 19:42:22 +01005512
5513static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5515 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5516 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5517 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5518 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5519 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5520 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5521 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 { } /* end */
5523};
5524
Takashi Iwaibec15c32008-01-28 18:16:30 +01005525/* update HP, line and mono out pins according to the master switch */
5526static void alc260_hp_master_update(struct hda_codec *codec,
5527 hda_nid_t hp, hda_nid_t line,
5528 hda_nid_t mono)
5529{
5530 struct alc_spec *spec = codec->spec;
5531 unsigned int val = spec->master_sw ? PIN_HP : 0;
5532 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005533 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005534 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005535 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005536 val);
5537 /* mono (speaker) depending on the HP jack sense */
5538 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005539 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005540 val);
5541}
5542
5543static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5544 struct snd_ctl_elem_value *ucontrol)
5545{
5546 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5547 struct alc_spec *spec = codec->spec;
5548 *ucontrol->value.integer.value = spec->master_sw;
5549 return 0;
5550}
5551
5552static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5553 struct snd_ctl_elem_value *ucontrol)
5554{
5555 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5556 struct alc_spec *spec = codec->spec;
5557 int val = !!*ucontrol->value.integer.value;
5558 hda_nid_t hp, line, mono;
5559
5560 if (val == spec->master_sw)
5561 return 0;
5562 spec->master_sw = val;
5563 hp = (kcontrol->private_value >> 16) & 0xff;
5564 line = (kcontrol->private_value >> 8) & 0xff;
5565 mono = kcontrol->private_value & 0xff;
5566 alc260_hp_master_update(codec, hp, line, mono);
5567 return 1;
5568}
5569
5570static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5571 {
5572 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5573 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005574 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005575 .info = snd_ctl_boolean_mono_info,
5576 .get = alc260_hp_master_sw_get,
5577 .put = alc260_hp_master_sw_put,
5578 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5579 },
5580 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5581 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5582 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5583 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5584 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5585 HDA_OUTPUT),
5586 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5587 { } /* end */
5588};
5589
5590static struct hda_verb alc260_hp_unsol_verbs[] = {
5591 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5592 {},
5593};
5594
5595static void alc260_hp_automute(struct hda_codec *codec)
5596{
5597 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005598
Wu Fengguang864f92b2009-11-18 12:38:02 +08005599 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005600 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5601}
5602
5603static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5604{
5605 if ((res >> 26) == ALC880_HP_EVENT)
5606 alc260_hp_automute(codec);
5607}
5608
Kailang Yangdf694da2005-12-05 19:42:22 +01005609static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005610 {
5611 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5612 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005613 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005614 .info = snd_ctl_boolean_mono_info,
5615 .get = alc260_hp_master_sw_get,
5616 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005617 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005618 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005619 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5620 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5621 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5622 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5623 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5624 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005625 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5626 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005627 { } /* end */
5628};
5629
Kailang Yang3f878302008-08-26 13:02:23 +02005630static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5631 .ops = &snd_hda_bind_vol,
5632 .values = {
5633 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5634 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5635 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5636 0
5637 },
5638};
5639
5640static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5641 .ops = &snd_hda_bind_sw,
5642 .values = {
5643 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5644 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5645 0
5646 },
5647};
5648
5649static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5650 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5651 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5652 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5653 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5654 { } /* end */
5655};
5656
Takashi Iwaibec15c32008-01-28 18:16:30 +01005657static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5658 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5659 {},
5660};
5661
5662static void alc260_hp_3013_automute(struct hda_codec *codec)
5663{
5664 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005665
Wu Fengguang864f92b2009-11-18 12:38:02 +08005666 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005667 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005668}
5669
5670static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5671 unsigned int res)
5672{
5673 if ((res >> 26) == ALC880_HP_EVENT)
5674 alc260_hp_3013_automute(codec);
5675}
5676
Kailang Yang3f878302008-08-26 13:02:23 +02005677static void alc260_hp_3012_automute(struct hda_codec *codec)
5678{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005679 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005680
Kailang Yang3f878302008-08-26 13:02:23 +02005681 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5682 bits);
5683 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5684 bits);
5685 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5686 bits);
5687}
5688
5689static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5690 unsigned int res)
5691{
5692 if ((res >> 26) == ALC880_HP_EVENT)
5693 alc260_hp_3012_automute(codec);
5694}
5695
5696/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005697 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5698 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005699static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005700 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005701 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005702 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005703 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5704 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5705 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5706 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005707 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005708 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5709 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005710 { } /* end */
5711};
5712
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005713/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5714 * versions of the ALC260 don't act on requests to enable mic bias from NID
5715 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5716 * datasheet doesn't mention this restriction. At this stage it's not clear
5717 * whether this behaviour is intentional or is a hardware bug in chip
5718 * revisions available in early 2006. Therefore for now allow the
5719 * "Headphone Jack Mode" control to span all choices, but if it turns out
5720 * that the lack of mic bias for this NID is intentional we could change the
5721 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5722 *
5723 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5724 * don't appear to make the mic bias available from the "line" jack, even
5725 * though the NID used for this jack (0x14) can supply it. The theory is
5726 * that perhaps Acer have included blocking capacitors between the ALC260
5727 * and the output jack. If this turns out to be the case for all such
5728 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5729 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005730 *
5731 * The C20x Tablet series have a mono internal speaker which is controlled
5732 * via the chip's Mono sum widget and pin complex, so include the necessary
5733 * controls for such models. On models without a "mono speaker" the control
5734 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005735 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005736static struct snd_kcontrol_new alc260_acer_mixer[] = {
5737 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5738 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005739 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005740 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005741 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005742 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005743 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005744 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5745 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5746 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5747 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5748 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5749 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5750 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5751 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005752 { } /* end */
5753};
5754
Michael Schwingencc959482009-02-22 18:58:45 +01005755/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5756 */
5757static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5758 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5759 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5760 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5761 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5762 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5763 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5764 { } /* end */
5765};
5766
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005767/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5768 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5769 */
5770static struct snd_kcontrol_new alc260_will_mixer[] = {
5771 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5772 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5773 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5774 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5775 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5776 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5777 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5778 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5779 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5780 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005781 { } /* end */
5782};
5783
5784/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5785 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5786 */
5787static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5788 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5789 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5790 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5791 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5792 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5793 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5794 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5795 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5796 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5797 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5798 { } /* end */
5799};
5800
Kailang Yangdf694da2005-12-05 19:42:22 +01005801/*
5802 * initialization verbs
5803 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804static struct hda_verb alc260_init_verbs[] = {
5805 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005808 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005810 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005812 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005814 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005816 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005818 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005820 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005822 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5823 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005824 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 /* set connection select to line in (default select for this ADC) */
5826 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005827 /* mute capture amp left and right */
5828 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5829 /* set connection select to line in (default select for this ADC) */
5830 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005831 /* set vol=0 Line-Out mixer amp left and right */
5832 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5833 /* unmute pin widget amp left and right (no gain on this amp) */
5834 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5835 /* set vol=0 HP mixer amp left and right */
5836 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5837 /* unmute pin widget amp left and right (no gain on this amp) */
5838 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5839 /* set vol=0 Mono mixer amp left and right */
5840 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5841 /* unmute pin widget amp left and right (no gain on this amp) */
5842 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5843 /* unmute LINE-2 out pin */
5844 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005845 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5846 * Line In 2 = 0x03
5847 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005848 /* mute analog inputs */
5849 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5850 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5851 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5852 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5853 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005855 /* mute Front out path */
5856 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5857 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5858 /* mute Headphone out path */
5859 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5860 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5861 /* mute Mono out path */
5862 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5863 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 { }
5865};
5866
Takashi Iwai474167d2006-05-17 17:17:43 +02005867#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005868static struct hda_verb alc260_hp_init_verbs[] = {
5869 /* Headphone and output */
5870 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5871 /* mono output */
5872 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5873 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5874 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5875 /* Mic2 (front panel) pin widget for input and vref at 80% */
5876 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5877 /* Line In pin widget for input */
5878 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5879 /* Line-2 pin widget for output */
5880 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5881 /* CD pin widget for input */
5882 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5883 /* unmute amp left and right */
5884 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5885 /* set connection select to line in (default select for this ADC) */
5886 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5887 /* unmute Line-Out mixer amp left and right (volume = 0) */
5888 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5889 /* mute pin widget amp left and right (no gain on this amp) */
5890 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5891 /* unmute HP mixer amp left and right (volume = 0) */
5892 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5893 /* mute pin widget amp left and right (no gain on this amp) */
5894 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005895 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5896 * Line In 2 = 0x03
5897 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005898 /* mute analog inputs */
5899 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5900 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5901 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5902 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5903 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005904 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5905 /* Unmute Front out path */
5906 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5907 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5908 /* Unmute Headphone out path */
5909 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5910 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5911 /* Unmute Mono out path */
5912 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5913 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5914 { }
5915};
Takashi Iwai474167d2006-05-17 17:17:43 +02005916#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005917
5918static struct hda_verb alc260_hp_3013_init_verbs[] = {
5919 /* Line out and output */
5920 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5921 /* mono output */
5922 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5923 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5924 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5925 /* Mic2 (front panel) pin widget for input and vref at 80% */
5926 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5927 /* Line In pin widget for input */
5928 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5929 /* Headphone pin widget for output */
5930 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5931 /* CD pin widget for input */
5932 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5933 /* unmute amp left and right */
5934 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5935 /* set connection select to line in (default select for this ADC) */
5936 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5937 /* unmute Line-Out mixer amp left and right (volume = 0) */
5938 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5939 /* mute pin widget amp left and right (no gain on this amp) */
5940 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5941 /* unmute HP mixer amp left and right (volume = 0) */
5942 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5943 /* mute pin widget amp left and right (no gain on this amp) */
5944 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005945 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5946 * Line In 2 = 0x03
5947 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005948 /* mute analog inputs */
5949 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5950 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5951 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5952 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5953 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005954 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5955 /* Unmute Front out path */
5956 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5957 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5958 /* Unmute Headphone out path */
5959 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5960 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5961 /* Unmute Mono out path */
5962 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5963 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5964 { }
5965};
5966
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005967/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005968 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5969 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005970 */
5971static struct hda_verb alc260_fujitsu_init_verbs[] = {
5972 /* Disable all GPIOs */
5973 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5974 /* Internal speaker is connected to headphone pin */
5975 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5976 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5977 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005978 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5979 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5980 /* Ensure all other unused pins are disabled and muted. */
5981 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5982 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005983 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005984 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005985 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005986 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5987 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5988 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005989
Jonathan Woithef7ace402006-02-28 11:46:14 +01005990 /* Disable digital (SPDIF) pins */
5991 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5992 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005993
Kailang Yangea1fb292008-08-26 12:58:38 +02005994 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005995 * when acting as an output.
5996 */
5997 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5998
5999 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006000 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6001 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6002 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6003 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6004 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6005 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6006 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6007 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6008 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006009
Jonathan Woithef7ace402006-02-28 11:46:14 +01006010 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6011 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6012 /* Unmute Line1 pin widget output buffer since it starts as an output.
6013 * If the pin mode is changed by the user the pin mode control will
6014 * take care of enabling the pin's input/output buffers as needed.
6015 * Therefore there's no need to enable the input buffer at this
6016 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006017 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006018 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006019 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006020 * mixer ctrl)
6021 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006022 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006023
Jonathan Woithef7ace402006-02-28 11:46:14 +01006024 /* Mute capture amp left and right */
6025 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006026 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006027 * in (on mic1 pin)
6028 */
6029 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006030
Jonathan Woithef7ace402006-02-28 11:46:14 +01006031 /* Do the same for the second ADC: mute capture input amp and
6032 * set ADC connection to line in (on mic1 pin)
6033 */
6034 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6035 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006036
Jonathan Woithef7ace402006-02-28 11:46:14 +01006037 /* Mute all inputs to mixer widget (even unconnected ones) */
6038 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6039 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6040 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6041 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6042 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6043 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6044 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6045 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006046
6047 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006048};
6049
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006050/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6051 * similar laptops (adapted from Fujitsu init verbs).
6052 */
6053static struct hda_verb alc260_acer_init_verbs[] = {
6054 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6055 * the headphone jack. Turn this on and rely on the standard mute
6056 * methods whenever the user wants to turn these outputs off.
6057 */
6058 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6059 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6060 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6061 /* Internal speaker/Headphone jack is connected to Line-out pin */
6062 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6063 /* Internal microphone/Mic jack is connected to Mic1 pin */
6064 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6065 /* Line In jack is connected to Line1 pin */
6066 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006067 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6068 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006069 /* Ensure all other unused pins are disabled and muted. */
6070 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6071 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006072 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6073 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6074 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6075 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6076 /* Disable digital (SPDIF) pins */
6077 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6078 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6079
Kailang Yangea1fb292008-08-26 12:58:38 +02006080 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006081 * bus when acting as outputs.
6082 */
6083 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6084 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6085
6086 /* Start with output sum widgets muted and their output gains at min */
6087 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6088 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6089 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6090 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6091 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6092 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6093 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6094 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6095 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6096
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006097 /* Unmute Line-out pin widget amp left and right
6098 * (no equiv mixer ctrl)
6099 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006100 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006101 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6102 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006103 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6104 * inputs. If the pin mode is changed by the user the pin mode control
6105 * will take care of enabling the pin's input/output buffers as needed.
6106 * Therefore there's no need to enable the input buffer at this
6107 * stage.
6108 */
6109 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6110 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6111
6112 /* Mute capture amp left and right */
6113 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6114 /* Set ADC connection select to match default mixer setting - mic
6115 * (on mic1 pin)
6116 */
6117 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6118
6119 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006120 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006121 */
6122 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006123 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006124
6125 /* Mute all inputs to mixer widget (even unconnected ones) */
6126 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6127 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6128 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6129 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6131 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6133 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6134
6135 { }
6136};
6137
Michael Schwingencc959482009-02-22 18:58:45 +01006138/* Initialisation sequence for Maxdata Favorit 100XS
6139 * (adapted from Acer init verbs).
6140 */
6141static struct hda_verb alc260_favorit100_init_verbs[] = {
6142 /* GPIO 0 enables the output jack.
6143 * Turn this on and rely on the standard mute
6144 * methods whenever the user wants to turn these outputs off.
6145 */
6146 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6147 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6148 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6149 /* Line/Mic input jack is connected to Mic1 pin */
6150 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6151 /* Ensure all other unused pins are disabled and muted. */
6152 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6153 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6154 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6155 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6156 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6157 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6158 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6159 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6160 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6161 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6162 /* Disable digital (SPDIF) pins */
6163 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6164 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6165
6166 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6167 * bus when acting as outputs.
6168 */
6169 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6170 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6171
6172 /* Start with output sum widgets muted and their output gains at min */
6173 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6174 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6175 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6176 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6177 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6178 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6179 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6180 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6181 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6182
6183 /* Unmute Line-out pin widget amp left and right
6184 * (no equiv mixer ctrl)
6185 */
6186 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6187 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6188 * inputs. If the pin mode is changed by the user the pin mode control
6189 * will take care of enabling the pin's input/output buffers as needed.
6190 * Therefore there's no need to enable the input buffer at this
6191 * stage.
6192 */
6193 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6194
6195 /* Mute capture amp left and right */
6196 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6197 /* Set ADC connection select to match default mixer setting - mic
6198 * (on mic1 pin)
6199 */
6200 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6201
6202 /* Do similar with the second ADC: mute capture input amp and
6203 * set ADC connection to mic to match ALSA's default state.
6204 */
6205 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6206 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6207
6208 /* Mute all inputs to mixer widget (even unconnected ones) */
6209 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6210 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6211 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6212 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6213 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6214 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6215 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6216 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6217
6218 { }
6219};
6220
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006221static struct hda_verb alc260_will_verbs[] = {
6222 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6223 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6224 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6225 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6226 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6227 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6228 {}
6229};
6230
6231static struct hda_verb alc260_replacer_672v_verbs[] = {
6232 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6233 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6234 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6235
6236 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6237 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6238 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6239
6240 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6241 {}
6242};
6243
6244/* toggle speaker-output according to the hp-jack state */
6245static void alc260_replacer_672v_automute(struct hda_codec *codec)
6246{
6247 unsigned int present;
6248
6249 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006250 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006251 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006252 snd_hda_codec_write_cache(codec, 0x01, 0,
6253 AC_VERB_SET_GPIO_DATA, 1);
6254 snd_hda_codec_write_cache(codec, 0x0f, 0,
6255 AC_VERB_SET_PIN_WIDGET_CONTROL,
6256 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006257 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006258 snd_hda_codec_write_cache(codec, 0x01, 0,
6259 AC_VERB_SET_GPIO_DATA, 0);
6260 snd_hda_codec_write_cache(codec, 0x0f, 0,
6261 AC_VERB_SET_PIN_WIDGET_CONTROL,
6262 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006263 }
6264}
6265
6266static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6267 unsigned int res)
6268{
6269 if ((res >> 26) == ALC880_HP_EVENT)
6270 alc260_replacer_672v_automute(codec);
6271}
6272
Kailang Yang3f878302008-08-26 13:02:23 +02006273static struct hda_verb alc260_hp_dc7600_verbs[] = {
6274 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6275 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6276 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6277 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6278 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6279 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6280 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6281 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6282 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6283 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6284 {}
6285};
6286
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006287/* Test configuration for debugging, modelled after the ALC880 test
6288 * configuration.
6289 */
6290#ifdef CONFIG_SND_DEBUG
6291static hda_nid_t alc260_test_dac_nids[1] = {
6292 0x02,
6293};
6294static hda_nid_t alc260_test_adc_nids[2] = {
6295 0x04, 0x05,
6296};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006297/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006298 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006299 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006300 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006301static struct hda_input_mux alc260_test_capture_sources[2] = {
6302 {
6303 .num_items = 7,
6304 .items = {
6305 { "MIC1 pin", 0x0 },
6306 { "MIC2 pin", 0x1 },
6307 { "LINE1 pin", 0x2 },
6308 { "LINE2 pin", 0x3 },
6309 { "CD pin", 0x4 },
6310 { "LINE-OUT pin", 0x5 },
6311 { "HP-OUT pin", 0x6 },
6312 },
6313 },
6314 {
6315 .num_items = 8,
6316 .items = {
6317 { "MIC1 pin", 0x0 },
6318 { "MIC2 pin", 0x1 },
6319 { "LINE1 pin", 0x2 },
6320 { "LINE2 pin", 0x3 },
6321 { "CD pin", 0x4 },
6322 { "Mixer", 0x5 },
6323 { "LINE-OUT pin", 0x6 },
6324 { "HP-OUT pin", 0x7 },
6325 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006326 },
6327};
6328static struct snd_kcontrol_new alc260_test_mixer[] = {
6329 /* Output driver widgets */
6330 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6331 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6332 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6333 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6334 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6335 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6336
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006337 /* Modes for retasking pin widgets
6338 * Note: the ALC260 doesn't seem to act on requests to enable mic
6339 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6340 * mention this restriction. At this stage it's not clear whether
6341 * this behaviour is intentional or is a hardware bug in chip
6342 * revisions available at least up until early 2006. Therefore for
6343 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6344 * choices, but if it turns out that the lack of mic bias for these
6345 * NIDs is intentional we could change their modes from
6346 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6347 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006348 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6349 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6350 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6351 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6352 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6353 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6354
6355 /* Loopback mixer controls */
6356 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6357 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6358 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6359 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6360 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6361 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6362 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6363 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6364 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6365 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006366 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6367 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6368 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6369 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006370
6371 /* Controls for GPIO pins, assuming they are configured as outputs */
6372 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6373 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6374 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6375 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6376
Jonathan Woithe92621f12006-02-28 11:47:47 +01006377 /* Switches to allow the digital IO pins to be enabled. The datasheet
6378 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006379 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006380 */
6381 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6382 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6383
Jonathan Woithef8225f62008-01-08 12:16:54 +01006384 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6385 * this output to turn on an external amplifier.
6386 */
6387 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6388 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6389
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006390 { } /* end */
6391};
6392static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006393 /* Enable all GPIOs as outputs with an initial value of 0 */
6394 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6395 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6396 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6397
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006398 /* Enable retasking pins as output, initially without power amp */
6399 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6400 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6401 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6402 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6403 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6404 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6405
Jonathan Woithe92621f12006-02-28 11:47:47 +01006406 /* Disable digital (SPDIF) pins initially, but users can enable
6407 * them via a mixer switch. In the case of SPDIF-out, this initverb
6408 * payload also sets the generation to 0, output to be in "consumer"
6409 * PCM format, copyright asserted, no pre-emphasis and no validity
6410 * control.
6411 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006412 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6413 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6414
Kailang Yangea1fb292008-08-26 12:58:38 +02006415 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006416 * OUT1 sum bus when acting as an output.
6417 */
6418 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6419 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6420 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6421 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6422
6423 /* Start with output sum widgets muted and their output gains at min */
6424 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6425 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6426 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6427 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6428 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6429 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6430 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6431 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6432 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6433
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006434 /* Unmute retasking pin widget output buffers since the default
6435 * state appears to be output. As the pin mode is changed by the
6436 * user the pin mode control will take care of enabling the pin's
6437 * input/output buffers as needed.
6438 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006439 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6440 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6441 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6442 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6443 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6444 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6445 /* Also unmute the mono-out pin widget */
6446 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6447
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006448 /* Mute capture amp left and right */
6449 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006450 /* Set ADC connection select to match default mixer setting (mic1
6451 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006452 */
6453 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6454
6455 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006456 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006457 */
6458 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6459 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6460
6461 /* Mute all inputs to mixer widget (even unconnected ones) */
6462 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6463 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6464 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6465 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6469 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6470
6471 { }
6472};
6473#endif
6474
Takashi Iwai63300792008-01-24 15:31:36 +01006475#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6476#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006478#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6479#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6480
Kailang Yangdf694da2005-12-05 19:42:22 +01006481/*
6482 * for BIOS auto-configuration
6483 */
6484
6485static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006486 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006487{
6488 hda_nid_t nid_vol;
6489 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006490 int err;
6491
6492 if (nid >= 0x0f && nid < 0x11) {
6493 nid_vol = nid - 0x7;
6494 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6495 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6496 } else if (nid == 0x11) {
6497 nid_vol = nid - 0x7;
6498 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6499 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6500 } else if (nid >= 0x12 && nid <= 0x15) {
6501 nid_vol = 0x08;
6502 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6503 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6504 } else
6505 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006506
Takashi Iwai863b4512008-10-21 17:01:47 +02006507 if (!(*vol_bits & (1 << nid_vol))) {
6508 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006509 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006510 if (err < 0)
6511 return err;
6512 *vol_bits |= (1 << nid_vol);
6513 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006514 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006515 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006516 return err;
6517 return 1;
6518}
6519
6520/* add playback controls from the parsed DAC table */
6521static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6522 const struct auto_pin_cfg *cfg)
6523{
6524 hda_nid_t nid;
6525 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006526 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006527
6528 spec->multiout.num_dacs = 1;
6529 spec->multiout.dac_nids = spec->private_dac_nids;
6530 spec->multiout.dac_nids[0] = 0x02;
6531
6532 nid = cfg->line_out_pins[0];
6533 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006534 const char *pfx;
6535 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6536 pfx = "Master";
6537 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6538 pfx = "Speaker";
6539 else
6540 pfx = "Front";
6541 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006542 if (err < 0)
6543 return err;
6544 }
6545
Takashi Iwai82bc9552006-03-21 11:24:42 +01006546 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006547 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006548 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006549 if (err < 0)
6550 return err;
6551 }
6552
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006553 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006554 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006555 err = alc260_add_playback_controls(spec, nid, "Headphone",
6556 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006557 if (err < 0)
6558 return err;
6559 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006560 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006561}
6562
6563/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006564static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006565 const struct auto_pin_cfg *cfg)
6566{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006567 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006568}
6569
6570static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6571 hda_nid_t nid, int pin_type,
6572 int sel_idx)
6573{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006574 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006575 /* need the manual connection? */
6576 if (nid >= 0x12) {
6577 int idx = nid - 0x12;
6578 snd_hda_codec_write(codec, idx + 0x0b, 0,
6579 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006580 }
6581}
6582
6583static void alc260_auto_init_multi_out(struct hda_codec *codec)
6584{
6585 struct alc_spec *spec = codec->spec;
6586 hda_nid_t nid;
6587
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006588 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006589 if (nid) {
6590 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6591 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6592 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006593
Takashi Iwai82bc9552006-03-21 11:24:42 +01006594 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006595 if (nid)
6596 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6597
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006598 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006599 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006600 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006601}
Kailang Yangdf694da2005-12-05 19:42:22 +01006602
6603#define ALC260_PIN_CD_NID 0x16
6604static void alc260_auto_init_analog_input(struct hda_codec *codec)
6605{
6606 struct alc_spec *spec = codec->spec;
6607 int i;
6608
6609 for (i = 0; i < AUTO_PIN_LAST; i++) {
6610 hda_nid_t nid = spec->autocfg.input_pins[i];
6611 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006612 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006613 if (nid != ALC260_PIN_CD_NID &&
6614 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006615 snd_hda_codec_write(codec, nid, 0,
6616 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006617 AMP_OUT_MUTE);
6618 }
6619 }
6620}
6621
Takashi Iwai7f311a42010-04-09 17:32:23 +02006622#define alc260_auto_init_input_src alc880_auto_init_input_src
6623
Kailang Yangdf694da2005-12-05 19:42:22 +01006624/*
6625 * generic initialization of ADC, input mixers and output mixers
6626 */
6627static struct hda_verb alc260_volume_init_verbs[] = {
6628 /*
6629 * Unmute ADC0-1 and set the default input to mic-in
6630 */
6631 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6632 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6633 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6634 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006635
Kailang Yangdf694da2005-12-05 19:42:22 +01006636 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6637 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006638 * Note: PASD motherboards uses the Line In 2 as the input for
6639 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006640 */
6641 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006642 /* mute analog inputs */
6643 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6644 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6645 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6646 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6647 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006648
6649 /*
6650 * Set up output mixers (0x08 - 0x0a)
6651 */
6652 /* set vol=0 to output mixers */
6653 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6654 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6655 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6656 /* set up input amps for analog loopback */
6657 /* Amp Indices: DAC = 0, mixer = 1 */
6658 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6659 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6660 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6661 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6662 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6663 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006664
Kailang Yangdf694da2005-12-05 19:42:22 +01006665 { }
6666};
6667
6668static int alc260_parse_auto_config(struct hda_codec *codec)
6669{
6670 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006671 int err;
6672 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6673
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006674 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6675 alc260_ignore);
6676 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006677 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006678 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6679 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006680 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006681 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006682 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006683 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006684 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006685 return err;
6686
6687 spec->multiout.max_channels = 2;
6688
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006689 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006690 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006691 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006692 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006693
Takashi Iwaid88897e2008-10-31 15:01:37 +01006694 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006695
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006696 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006697 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006698
Kailang Yang6227cdc2010-02-25 08:36:52 +01006699 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006700
Kailang Yangdf694da2005-12-05 19:42:22 +01006701 return 1;
6702}
6703
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006704/* additional initialization for auto-configuration model */
6705static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006706{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006707 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006708 alc260_auto_init_multi_out(codec);
6709 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02006710 alc260_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006711 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006712 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006713}
6714
Takashi Iwaicb53c622007-08-10 17:21:45 +02006715#ifdef CONFIG_SND_HDA_POWER_SAVE
6716static struct hda_amp_list alc260_loopbacks[] = {
6717 { 0x07, HDA_INPUT, 0 },
6718 { 0x07, HDA_INPUT, 1 },
6719 { 0x07, HDA_INPUT, 2 },
6720 { 0x07, HDA_INPUT, 3 },
6721 { 0x07, HDA_INPUT, 4 },
6722 { } /* end */
6723};
6724#endif
6725
Kailang Yangdf694da2005-12-05 19:42:22 +01006726/*
6727 * ALC260 configurations
6728 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006729static const char *alc260_models[ALC260_MODEL_LAST] = {
6730 [ALC260_BASIC] = "basic",
6731 [ALC260_HP] = "hp",
6732 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006733 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006734 [ALC260_FUJITSU_S702X] = "fujitsu",
6735 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006736 [ALC260_WILL] = "will",
6737 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006738 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006739#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006740 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006741#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006742 [ALC260_AUTO] = "auto",
6743};
6744
6745static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006746 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006747 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006748 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006749 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006750 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006751 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006752 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006753 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006754 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006755 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6756 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6757 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6758 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6759 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6760 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6761 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6762 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6763 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006764 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006765 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006766 {}
6767};
6768
Kailang Yangdf694da2005-12-05 19:42:22 +01006769static struct alc_config_preset alc260_presets[] = {
6770 [ALC260_BASIC] = {
6771 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006772 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006773 .init_verbs = { alc260_init_verbs },
6774 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6775 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006776 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01006777 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006778 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6779 .channel_mode = alc260_modes,
6780 .input_mux = &alc260_capture_source,
6781 },
6782 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006783 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006784 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006785 .init_verbs = { alc260_init_verbs,
6786 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006787 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6788 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006789 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6790 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006791 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6792 .channel_mode = alc260_modes,
6793 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006794 .unsol_event = alc260_hp_unsol_event,
6795 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006796 },
Kailang Yang3f878302008-08-26 13:02:23 +02006797 [ALC260_HP_DC7600] = {
6798 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006799 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006800 .init_verbs = { alc260_init_verbs,
6801 alc260_hp_dc7600_verbs },
6802 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6803 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006804 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6805 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006806 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6807 .channel_mode = alc260_modes,
6808 .input_mux = &alc260_capture_source,
6809 .unsol_event = alc260_hp_3012_unsol_event,
6810 .init_hook = alc260_hp_3012_automute,
6811 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006812 [ALC260_HP_3013] = {
6813 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006814 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006815 .init_verbs = { alc260_hp_3013_init_verbs,
6816 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006817 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6818 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006819 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6820 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006821 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6822 .channel_mode = alc260_modes,
6823 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006824 .unsol_event = alc260_hp_3013_unsol_event,
6825 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006826 },
6827 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006828 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006829 .init_verbs = { alc260_fujitsu_init_verbs },
6830 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6831 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006832 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6833 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006834 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6835 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006836 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6837 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006838 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006839 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006840 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006841 .init_verbs = { alc260_acer_init_verbs },
6842 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6843 .dac_nids = alc260_dac_nids,
6844 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6845 .adc_nids = alc260_dual_adc_nids,
6846 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6847 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006848 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6849 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006850 },
Michael Schwingencc959482009-02-22 18:58:45 +01006851 [ALC260_FAVORIT100] = {
6852 .mixers = { alc260_favorit100_mixer },
6853 .init_verbs = { alc260_favorit100_init_verbs },
6854 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6855 .dac_nids = alc260_dac_nids,
6856 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6857 .adc_nids = alc260_dual_adc_nids,
6858 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6859 .channel_mode = alc260_modes,
6860 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6861 .input_mux = alc260_favorit100_capture_sources,
6862 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006863 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006864 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006865 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6866 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6867 .dac_nids = alc260_dac_nids,
6868 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6869 .adc_nids = alc260_adc_nids,
6870 .dig_out_nid = ALC260_DIGOUT_NID,
6871 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6872 .channel_mode = alc260_modes,
6873 .input_mux = &alc260_capture_source,
6874 },
6875 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006876 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006877 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6878 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6879 .dac_nids = alc260_dac_nids,
6880 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6881 .adc_nids = alc260_adc_nids,
6882 .dig_out_nid = ALC260_DIGOUT_NID,
6883 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6884 .channel_mode = alc260_modes,
6885 .input_mux = &alc260_capture_source,
6886 .unsol_event = alc260_replacer_672v_unsol_event,
6887 .init_hook = alc260_replacer_672v_automute,
6888 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006889#ifdef CONFIG_SND_DEBUG
6890 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006891 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006892 .init_verbs = { alc260_test_init_verbs },
6893 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6894 .dac_nids = alc260_test_dac_nids,
6895 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6896 .adc_nids = alc260_test_adc_nids,
6897 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6898 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006899 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6900 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006901 },
6902#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006903};
6904
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905static int patch_alc260(struct hda_codec *codec)
6906{
6907 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006908 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006909
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006910 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006911 if (spec == NULL)
6912 return -ENOMEM;
6913
6914 codec->spec = spec;
6915
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006916 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6917 alc260_models,
6918 alc260_cfg_tbl);
6919 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006920 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006921 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006922 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006923 }
6924
Kailang Yangdf694da2005-12-05 19:42:22 +01006925 if (board_config == ALC260_AUTO) {
6926 /* automatic parse from the BIOS config */
6927 err = alc260_parse_auto_config(codec);
6928 if (err < 0) {
6929 alc_free(codec);
6930 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006931 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006932 printk(KERN_INFO
6933 "hda_codec: Cannot set up configuration "
6934 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006935 board_config = ALC260_BASIC;
6936 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006938
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006939 err = snd_hda_attach_beep_device(codec, 0x1);
6940 if (err < 0) {
6941 alc_free(codec);
6942 return err;
6943 }
6944
Kailang Yangdf694da2005-12-05 19:42:22 +01006945 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02006946 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006947
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6949 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6950
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006951 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6952 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6953
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006954 if (!spec->adc_nids && spec->input_mux) {
6955 /* check whether NID 0x04 is valid */
6956 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02006957 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006958 /* get type */
6959 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6960 spec->adc_nids = alc260_adc_nids_alt;
6961 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6962 } else {
6963 spec->adc_nids = alc260_adc_nids;
6964 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6965 }
6966 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006967 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006968 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006969
Takashi Iwai2134ea42008-01-10 16:53:55 +01006970 spec->vmaster_nid = 0x08;
6971
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006973 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006974 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006975#ifdef CONFIG_SND_HDA_POWER_SAVE
6976 if (!spec->loopback.amplist)
6977 spec->loopback.amplist = alc260_loopbacks;
6978#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979
6980 return 0;
6981}
6982
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006983
Linus Torvalds1da177e2005-04-16 15:20:36 -07006984/*
Takashi Iwai49535502009-06-30 15:28:30 +02006985 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986 *
6987 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6988 * configuration. Each pin widget can choose any input DACs and a mixer.
6989 * Each ADC is connected from a mixer of all inputs. This makes possible
6990 * 6-channel independent captures.
6991 *
6992 * In addition, an independent DAC for the multi-playback (not used in this
6993 * driver yet).
6994 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006995#define ALC882_DIGOUT_NID 0x06
6996#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02006997#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
6998#define ALC883_DIGIN_NID ALC882_DIGIN_NID
6999#define ALC1200_DIGOUT_NID 0x10
7000
Linus Torvalds1da177e2005-04-16 15:20:36 -07007001
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007002static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007003 { 8, NULL }
7004};
7005
Takashi Iwai49535502009-06-30 15:28:30 +02007006/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007static hda_nid_t alc882_dac_nids[4] = {
7008 /* front, rear, clfe, rear_surr */
7009 0x02, 0x03, 0x04, 0x05
7010};
Takashi Iwai49535502009-06-30 15:28:30 +02007011#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007012
Takashi Iwai49535502009-06-30 15:28:30 +02007013/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007014#define alc882_adc_nids alc880_adc_nids
7015#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007016#define alc883_adc_nids alc882_adc_nids_alt
7017static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7018static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7019#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020
Takashi Iwaie1406342008-02-11 18:32:32 +01007021static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7022static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007023#define alc883_capsrc_nids alc882_capsrc_nids_alt
7024static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7025#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007026
Linus Torvalds1da177e2005-04-16 15:20:36 -07007027/* input MUX */
7028/* FIXME: should be a matrix-type input source selection */
7029
7030static struct hda_input_mux alc882_capture_source = {
7031 .num_items = 4,
7032 .items = {
7033 { "Mic", 0x0 },
7034 { "Front Mic", 0x1 },
7035 { "Line", 0x2 },
7036 { "CD", 0x4 },
7037 },
7038};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007039
Takashi Iwai49535502009-06-30 15:28:30 +02007040#define alc883_capture_source alc882_capture_source
7041
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007042static struct hda_input_mux alc889_capture_source = {
7043 .num_items = 3,
7044 .items = {
7045 { "Front Mic", 0x0 },
7046 { "Mic", 0x3 },
7047 { "Line", 0x2 },
7048 },
7049};
7050
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007051static struct hda_input_mux mb5_capture_source = {
7052 .num_items = 3,
7053 .items = {
7054 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307055 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007056 { "CD", 0x4 },
7057 },
7058};
7059
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007060static struct hda_input_mux macmini3_capture_source = {
7061 .num_items = 2,
7062 .items = {
7063 { "Line", 0x2 },
7064 { "CD", 0x4 },
7065 },
7066};
7067
Takashi Iwai49535502009-06-30 15:28:30 +02007068static struct hda_input_mux alc883_3stack_6ch_intel = {
7069 .num_items = 4,
7070 .items = {
7071 { "Mic", 0x1 },
7072 { "Front Mic", 0x0 },
7073 { "Line", 0x2 },
7074 { "CD", 0x4 },
7075 },
7076};
7077
7078static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7079 .num_items = 2,
7080 .items = {
7081 { "Mic", 0x1 },
7082 { "Line", 0x2 },
7083 },
7084};
7085
7086static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7087 .num_items = 4,
7088 .items = {
7089 { "Mic", 0x0 },
7090 { "iMic", 0x1 },
7091 { "Line", 0x2 },
7092 { "CD", 0x4 },
7093 },
7094};
7095
7096static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7097 .num_items = 2,
7098 .items = {
7099 { "Mic", 0x0 },
7100 { "Int Mic", 0x1 },
7101 },
7102};
7103
7104static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7105 .num_items = 3,
7106 .items = {
7107 { "Mic", 0x0 },
7108 { "Front Mic", 0x1 },
7109 { "Line", 0x4 },
7110 },
7111};
7112
7113static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7114 .num_items = 2,
7115 .items = {
7116 { "Mic", 0x0 },
7117 { "Line", 0x2 },
7118 },
7119};
7120
7121static struct hda_input_mux alc889A_mb31_capture_source = {
7122 .num_items = 2,
7123 .items = {
7124 { "Mic", 0x0 },
7125 /* Front Mic (0x01) unused */
7126 { "Line", 0x2 },
7127 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007128 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007129 },
7130};
7131
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007132static struct hda_input_mux alc889A_imac91_capture_source = {
7133 .num_items = 2,
7134 .items = {
7135 { "Mic", 0x01 },
7136 { "Line", 0x2 }, /* Not sure! */
7137 },
7138};
7139
Takashi Iwai49535502009-06-30 15:28:30 +02007140/*
7141 * 2ch mode
7142 */
7143static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7144 { 2, NULL }
7145};
7146
Kailang Yangdf694da2005-12-05 19:42:22 +01007147/*
Kailang Yang272a5272007-05-14 11:00:38 +02007148 * 2ch mode
7149 */
7150static struct hda_verb alc882_3ST_ch2_init[] = {
7151 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7152 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7153 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7154 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7155 { } /* end */
7156};
7157
7158/*
Takashi Iwai49535502009-06-30 15:28:30 +02007159 * 4ch mode
7160 */
7161static struct hda_verb alc882_3ST_ch4_init[] = {
7162 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7163 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7164 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7165 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7166 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7167 { } /* end */
7168};
7169
7170/*
Kailang Yang272a5272007-05-14 11:00:38 +02007171 * 6ch mode
7172 */
7173static struct hda_verb alc882_3ST_ch6_init[] = {
7174 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7175 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7176 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7177 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7178 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7179 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7180 { } /* end */
7181};
7182
Takashi Iwai49535502009-06-30 15:28:30 +02007183static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007184 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007185 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007186 { 6, alc882_3ST_ch6_init },
7187};
7188
Takashi Iwai49535502009-06-30 15:28:30 +02007189#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7190
Kailang Yang272a5272007-05-14 11:00:38 +02007191/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307192 * 2ch mode
7193 */
7194static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7195 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7196 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7197 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7198 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7199 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7200 { } /* end */
7201};
7202
7203/*
7204 * 4ch mode
7205 */
7206static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7207 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7208 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7209 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7210 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7211 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7212 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7213 { } /* end */
7214};
7215
7216/*
7217 * 6ch mode
7218 */
7219static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7220 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7221 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7222 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7223 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7224 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7225 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7226 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7227 { } /* end */
7228};
7229
7230static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7231 { 2, alc883_3ST_ch2_clevo_init },
7232 { 4, alc883_3ST_ch4_clevo_init },
7233 { 6, alc883_3ST_ch6_clevo_init },
7234};
7235
7236
7237/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007238 * 6ch mode
7239 */
7240static struct hda_verb alc882_sixstack_ch6_init[] = {
7241 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7242 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7243 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7244 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7245 { } /* end */
7246};
7247
7248/*
7249 * 8ch mode
7250 */
7251static struct hda_verb alc882_sixstack_ch8_init[] = {
7252 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7253 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7254 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7255 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7256 { } /* end */
7257};
7258
7259static struct hda_channel_mode alc882_sixstack_modes[2] = {
7260 { 6, alc882_sixstack_ch6_init },
7261 { 8, alc882_sixstack_ch8_init },
7262};
7263
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007264
7265/* Macbook Air 2,1 */
7266
7267static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7268 { 2, NULL },
7269};
7270
Takashi Iwai87350ad2007-08-16 18:19:38 +02007271/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007272 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007273 */
7274
7275/*
7276 * 2ch mode
7277 */
7278static struct hda_verb alc885_mbp_ch2_init[] = {
7279 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7280 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7281 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7282 { } /* end */
7283};
7284
7285/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007286 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007287 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007288static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007289 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7290 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7291 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7292 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7293 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7294 { } /* end */
7295};
7296
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007297static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007298 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007299 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007300};
7301
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007302/*
7303 * 2ch
7304 * Speakers/Woofer/HP = Front
7305 * LineIn = Input
7306 */
7307static struct hda_verb alc885_mb5_ch2_init[] = {
7308 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7309 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7310 { } /* end */
7311};
7312
7313/*
7314 * 6ch mode
7315 * Speakers/HP = Front
7316 * Woofer = LFE
7317 * LineIn = Surround
7318 */
7319static struct hda_verb alc885_mb5_ch6_init[] = {
7320 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7321 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7322 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7323 { } /* end */
7324};
7325
7326static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7327 { 2, alc885_mb5_ch2_init },
7328 { 6, alc885_mb5_ch6_init },
7329};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007330
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007331#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007332
7333/*
7334 * 2ch mode
7335 */
7336static struct hda_verb alc883_4ST_ch2_init[] = {
7337 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7338 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7339 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7340 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7341 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7342 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7343 { } /* end */
7344};
7345
7346/*
7347 * 4ch mode
7348 */
7349static struct hda_verb alc883_4ST_ch4_init[] = {
7350 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7351 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7352 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7353 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7354 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7355 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7356 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7357 { } /* end */
7358};
7359
7360/*
7361 * 6ch mode
7362 */
7363static struct hda_verb alc883_4ST_ch6_init[] = {
7364 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7365 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7366 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7367 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7368 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7369 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7370 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7371 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7372 { } /* end */
7373};
7374
7375/*
7376 * 8ch mode
7377 */
7378static struct hda_verb alc883_4ST_ch8_init[] = {
7379 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7380 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7381 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7382 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7383 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7384 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7385 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7386 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7387 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7388 { } /* end */
7389};
7390
7391static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7392 { 2, alc883_4ST_ch2_init },
7393 { 4, alc883_4ST_ch4_init },
7394 { 6, alc883_4ST_ch6_init },
7395 { 8, alc883_4ST_ch8_init },
7396};
7397
7398
7399/*
7400 * 2ch mode
7401 */
7402static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7403 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7404 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7405 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7406 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7407 { } /* end */
7408};
7409
7410/*
7411 * 4ch mode
7412 */
7413static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7414 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7415 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7416 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7417 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7418 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7419 { } /* end */
7420};
7421
7422/*
7423 * 6ch mode
7424 */
7425static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7426 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7427 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7428 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7429 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7430 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7431 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7432 { } /* end */
7433};
7434
7435static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7436 { 2, alc883_3ST_ch2_intel_init },
7437 { 4, alc883_3ST_ch4_intel_init },
7438 { 6, alc883_3ST_ch6_intel_init },
7439};
7440
7441/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007442 * 2ch mode
7443 */
7444static struct hda_verb alc889_ch2_intel_init[] = {
7445 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7446 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7447 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7448 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7449 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7450 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7451 { } /* end */
7452};
7453
7454/*
Takashi Iwai49535502009-06-30 15:28:30 +02007455 * 6ch mode
7456 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007457static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007458 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7459 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7460 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7461 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7462 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007463 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7464 { } /* end */
7465};
7466
7467/*
7468 * 8ch mode
7469 */
7470static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007471 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7472 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7473 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7474 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7475 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007476 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7477 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007478 { } /* end */
7479};
7480
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007481static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7482 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007483 { 6, alc889_ch6_intel_init },
7484 { 8, alc889_ch8_intel_init },
7485};
7486
7487/*
7488 * 6ch mode
7489 */
Takashi Iwai49535502009-06-30 15:28:30 +02007490static struct hda_verb alc883_sixstack_ch6_init[] = {
7491 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7492 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7493 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7494 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7495 { } /* end */
7496};
7497
7498/*
7499 * 8ch mode
7500 */
7501static struct hda_verb alc883_sixstack_ch8_init[] = {
7502 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7503 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7504 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7505 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7506 { } /* end */
7507};
7508
7509static struct hda_channel_mode alc883_sixstack_modes[2] = {
7510 { 6, alc883_sixstack_ch6_init },
7511 { 8, alc883_sixstack_ch8_init },
7512};
7513
7514
Linus Torvalds1da177e2005-04-16 15:20:36 -07007515/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7516 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7517 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01007518static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007519 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007520 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007521 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007522 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007523 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7524 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007525 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7526 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007527 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007528 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007529 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7530 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7531 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7532 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7533 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7534 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007535 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007536 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7537 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007538 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007539 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007540 { } /* end */
7541};
7542
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007543/* Macbook Air 2,1 same control for HP and internal Speaker */
7544
7545static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7546 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7547 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7548 { }
7549};
7550
7551
Takashi Iwai87350ad2007-08-16 18:19:38 +02007552static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007553 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7554 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7555 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7556 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7557 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007558 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7559 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007560 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7561 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007562 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007563 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7564 { } /* end */
7565};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007566
7567static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007568 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7569 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7570 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7571 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7572 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7573 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307574 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7575 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307576 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7577 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7579 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7580 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7581 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7582 { } /* end */
7583};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007584
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007585static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7586 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7587 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7588 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7589 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7590 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7591 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7592 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7593 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7594 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7595 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7596 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7597 { } /* end */
7598};
7599
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007600static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007601 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7602 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007603 { } /* end */
7604};
7605
7606
Kailang Yangbdd148a2007-05-08 15:19:08 +02007607static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7608 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7609 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7610 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7611 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7612 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7613 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7614 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7615 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7616 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007617 { } /* end */
7618};
7619
Kailang Yang272a5272007-05-14 11:00:38 +02007620static struct snd_kcontrol_new alc882_targa_mixer[] = {
7621 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7622 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7623 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7624 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7625 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7626 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7627 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7628 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7629 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007630 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007631 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7632 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007633 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007634 { } /* end */
7635};
7636
7637/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7638 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7639 */
7640static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7641 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7642 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7643 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7644 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7645 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7646 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7647 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7648 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7649 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7650 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7651 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7652 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007653 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007654 { } /* end */
7655};
7656
Takashi Iwai914759b2007-09-06 14:52:04 +02007657static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7658 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7659 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7660 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7661 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7662 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7663 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7664 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7665 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7666 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7667 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007668 { } /* end */
7669};
7670
Kailang Yangdf694da2005-12-05 19:42:22 +01007671static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7672 {
7673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7674 .name = "Channel Mode",
7675 .info = alc_ch_mode_info,
7676 .get = alc_ch_mode_get,
7677 .put = alc_ch_mode_put,
7678 },
7679 { } /* end */
7680};
7681
Takashi Iwai49535502009-06-30 15:28:30 +02007682static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007683 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7685 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007687 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7688 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007689 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007690 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7691 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007693 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7694 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007695
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007696 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007697 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007698 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007699 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007700 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007701 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007702 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007704 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007705 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007706 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007708 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007709 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007710 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007712 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007713 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007714 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7715 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007716 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007717 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7718 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007719 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007720 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7721 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7722 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7723 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7724 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007725 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007726 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007727
7728 /* FIXME: use matrix-type input source selection */
7729 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007730 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007731 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007732 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007733 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007734 /* ADC2: mute amp left and right */
7735 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007736 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007737 /* ADC3: mute amp left and right */
7738 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007739 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740
7741 { }
7742};
7743
Takashi Iwai49535502009-06-30 15:28:30 +02007744static struct hda_verb alc882_adc1_init_verbs[] = {
7745 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7746 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7747 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7748 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7749 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7750 /* ADC1: mute amp left and right */
7751 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7752 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7753 { }
7754};
7755
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007756static struct hda_verb alc882_eapd_verbs[] = {
7757 /* change to EAPD mode */
7758 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007759 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007760 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007761};
7762
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007763static struct hda_verb alc889_eapd_verbs[] = {
7764 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7765 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7766 { }
7767};
7768
Wu Fengguang6732bd02009-07-30 09:19:14 +02007769static struct hda_verb alc_hp15_unsol_verbs[] = {
7770 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7771 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7772 {}
7773};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007774
7775static struct hda_verb alc885_init_verbs[] = {
7776 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01007777 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7778 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007779 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007780 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7781 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007782 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007783 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7784 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007785 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007786 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7787 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007788
7789 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007790 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007791 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7792 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7793 /* Front Pin: output 0 (0x0c) */
7794 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7795 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7796 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7797 /* Rear Pin: output 1 (0x0d) */
7798 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7799 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7800 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7801 /* CLFE Pin: output 2 (0x0e) */
7802 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7803 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7804 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7805 /* Side Pin: output 3 (0x0f) */
7806 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7807 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7808 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7809 /* Mic (rear) pin: input vref at 80% */
7810 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7811 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7812 /* Front Mic pin: input vref at 80% */
7813 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7814 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7815 /* Line In pin: input */
7816 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7817 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7818
7819 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7820 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01007821 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007822 /* Input mixer2 */
7823 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007824 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01007825 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007826 /* ADC2: mute amp left and right */
7827 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7828 /* ADC3: mute amp left and right */
7829 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7830
7831 { }
7832};
7833
7834static struct hda_verb alc885_init_input_verbs[] = {
7835 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7836 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7837 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7838 { }
7839};
7840
7841
7842/* Unmute Selector 24h and set the default input to front mic */
7843static struct hda_verb alc889_init_input_verbs[] = {
7844 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7845 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7846 { }
7847};
7848
7849
Takashi Iwai49535502009-06-30 15:28:30 +02007850#define alc883_init_verbs alc882_base_init_verbs
7851
Tobin Davis9102cd12006-12-15 10:02:12 +01007852/* Mac Pro test */
7853static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7854 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7855 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7856 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7857 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7858 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007859 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007860 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7861 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007862 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007863 { } /* end */
7864};
7865
7866static struct hda_verb alc882_macpro_init_verbs[] = {
7867 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7868 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7869 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7870 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7871 /* Front Pin: output 0 (0x0c) */
7872 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7873 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7874 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7875 /* Front Mic pin: input vref at 80% */
7876 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7877 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7878 /* Speaker: output */
7879 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7880 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7881 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7882 /* Headphone output (output 0 - 0x0c) */
7883 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7884 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7885 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7886
7887 /* FIXME: use matrix-type input source selection */
7888 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7889 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7890 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7891 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7892 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7893 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7894 /* Input mixer2 */
7895 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7896 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7897 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7898 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7899 /* Input mixer3 */
7900 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7901 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7902 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7903 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7904 /* ADC1: mute amp left and right */
7905 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7906 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7907 /* ADC2: mute amp left and right */
7908 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7909 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7910 /* ADC3: mute amp left and right */
7911 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7912 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7913
7914 { }
7915};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007916
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007917/* Macbook 5,1 */
7918static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007919 /* DACs */
7920 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7921 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7922 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7923 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007924 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007925 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7926 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7927 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007928 /* Surround mixer */
7929 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7930 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7931 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7932 /* LFE mixer */
7933 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7934 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7935 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7936 /* HP mixer */
7937 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7938 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7939 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7940 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007941 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7942 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007943 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7944 /* LFE Pin (0x0e) */
7945 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7946 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7947 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
7948 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007949 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7950 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007951 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10307952 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007953 /* Front Mic pin: input vref at 80% */
7954 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7955 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7956 /* Line In pin */
7957 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7958 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7959
Alex Murrayb8f171e2010-06-14 12:08:43 +09307960 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
7961 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
7962 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007963 { }
7964};
7965
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007966/* Macmini 3,1 */
7967static struct hda_verb alc885_macmini3_init_verbs[] = {
7968 /* DACs */
7969 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7970 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7971 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7972 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7973 /* Front mixer */
7974 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7975 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7976 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7977 /* Surround mixer */
7978 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7979 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7980 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7981 /* LFE mixer */
7982 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7983 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7984 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7985 /* HP mixer */
7986 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7987 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7988 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7989 /* Front Pin (0x0c) */
7990 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7991 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7992 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7993 /* LFE Pin (0x0e) */
7994 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7995 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7996 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
7997 /* HP Pin (0x0f) */
7998 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7999 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8000 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8001 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8002 /* Line In pin */
8003 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8004 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8005
8006 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8007 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8008 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8009 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8010 { }
8011};
8012
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008013
8014static struct hda_verb alc885_mba21_init_verbs[] = {
8015 /*Internal and HP Speaker Mixer*/
8016 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8017 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8018 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8019 /*Internal Speaker Pin (0x0c)*/
8020 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8021 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8022 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8023 /* HP Pin: output 0 (0x0e) */
8024 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8025 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8026 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8027 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8028 /* Line in (is hp when jack connected)*/
8029 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8030 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8031
8032 { }
8033 };
8034
8035
Takashi Iwai87350ad2007-08-16 18:19:38 +02008036/* Macbook Pro rev3 */
8037static struct hda_verb alc885_mbp3_init_verbs[] = {
8038 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8039 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8040 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8041 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8042 /* Rear mixer */
8043 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8044 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8045 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008046 /* HP mixer */
8047 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8048 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8049 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008050 /* Front Pin: output 0 (0x0c) */
8051 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8052 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8053 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008054 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008055 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008056 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8057 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008058 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8059 /* Mic (rear) pin: input vref at 80% */
8060 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8061 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8062 /* Front Mic pin: input vref at 80% */
8063 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8064 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8065 /* Line In pin: use output 1 when in LineOut mode */
8066 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8067 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8068 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8069
8070 /* FIXME: use matrix-type input source selection */
8071 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8072 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8073 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8074 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8075 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8076 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8077 /* Input mixer2 */
8078 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8079 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8080 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8081 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8082 /* Input mixer3 */
8083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8087 /* ADC1: mute amp left and right */
8088 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8089 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8090 /* ADC2: mute amp left and right */
8091 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8092 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8093 /* ADC3: mute amp left and right */
8094 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8095 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8096
8097 { }
8098};
8099
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008100/* iMac 9,1 */
8101static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008102 /* Internal Speaker Pin (0x0c) */
8103 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8104 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8105 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8106 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8107 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8108 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8109 /* HP Pin: Rear */
8110 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8111 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8112 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8113 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8114 /* Line in Rear */
8115 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8116 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8117 /* Front Mic pin: input vref at 80% */
8118 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8119 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008120 /* Rear mixer */
8121 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8122 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8123 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008124 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8125 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8126 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8127 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8128 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008129 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8130 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8131 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8132 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008133 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008134 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8135 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8136 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8137 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008138 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008139 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8140 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8141 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8142 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008143 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008144 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8145 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008146 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008147 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8148 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008149 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008150 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8151 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008152 { }
8153};
8154
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008155/* iMac 24 mixer. */
8156static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8157 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8158 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8159 { } /* end */
8160};
8161
8162/* iMac 24 init verbs. */
8163static struct hda_verb alc885_imac24_init_verbs[] = {
8164 /* Internal speakers: output 0 (0x0c) */
8165 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8166 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8167 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8168 /* Internal speakers: output 0 (0x0c) */
8169 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8170 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8171 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8172 /* Headphone: output 0 (0x0c) */
8173 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8174 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8175 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8176 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8177 /* Front Mic: input vref at 80% */
8178 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8179 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8180 { }
8181};
8182
8183/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008184static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008185{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008186 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008187
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008188 spec->autocfg.hp_pins[0] = 0x14;
8189 spec->autocfg.speaker_pins[0] = 0x18;
8190 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008191}
8192
Takashi Iwai9d54f082010-02-22 08:34:40 +01008193#define alc885_mb5_setup alc885_imac24_setup
8194#define alc885_macmini3_setup alc885_imac24_setup
8195
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008196/* Macbook Air 2,1 */
8197static void alc885_mba21_setup(struct hda_codec *codec)
8198{
8199 struct alc_spec *spec = codec->spec;
8200
8201 spec->autocfg.hp_pins[0] = 0x14;
8202 spec->autocfg.speaker_pins[0] = 0x18;
8203}
8204
8205
8206
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008207static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008208{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008209 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008210
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008211 spec->autocfg.hp_pins[0] = 0x15;
8212 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008213}
8214
Takashi Iwai9d54f082010-02-22 08:34:40 +01008215static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308216{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008217 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308218
Takashi Iwai9d54f082010-02-22 08:34:40 +01008219 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008220 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008221 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008222}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008223
Kailang Yang272a5272007-05-14 11:00:38 +02008224static struct hda_verb alc882_targa_verbs[] = {
8225 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8226 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8227
8228 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8229 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008230
Kailang Yang272a5272007-05-14 11:00:38 +02008231 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8232 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8233 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8234
8235 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008236 { } /* end */
8237};
8238
8239/* toggle speaker-output according to the hp-jack state */
8240static void alc882_targa_automute(struct hda_codec *codec)
8241{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008242 struct alc_spec *spec = codec->spec;
8243 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008244 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008245 spec->jack_present ? 1 : 3);
8246}
8247
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008248static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008249{
8250 struct alc_spec *spec = codec->spec;
8251
8252 spec->autocfg.hp_pins[0] = 0x14;
8253 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008254}
8255
8256static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8257{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008258 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008259 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008260}
8261
8262static struct hda_verb alc882_asus_a7j_verbs[] = {
8263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8264 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8265
8266 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8267 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8268 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008269
Kailang Yang272a5272007-05-14 11:00:38 +02008270 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8271 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8272 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8273
8274 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8275 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8276 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8277 { } /* end */
8278};
8279
Takashi Iwai914759b2007-09-06 14:52:04 +02008280static struct hda_verb alc882_asus_a7m_verbs[] = {
8281 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8282 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8283
8284 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8285 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8286 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008287
Takashi Iwai914759b2007-09-06 14:52:04 +02008288 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8289 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8290 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8291
8292 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8293 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8294 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8295 { } /* end */
8296};
8297
Tobin Davis9102cd12006-12-15 10:02:12 +01008298static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8299{
8300 unsigned int gpiostate, gpiomask, gpiodir;
8301
8302 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8303 AC_VERB_GET_GPIO_DATA, 0);
8304
8305 if (!muted)
8306 gpiostate |= (1 << pin);
8307 else
8308 gpiostate &= ~(1 << pin);
8309
8310 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8311 AC_VERB_GET_GPIO_MASK, 0);
8312 gpiomask |= (1 << pin);
8313
8314 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8315 AC_VERB_GET_GPIO_DIRECTION, 0);
8316 gpiodir |= (1 << pin);
8317
8318
8319 snd_hda_codec_write(codec, codec->afg, 0,
8320 AC_VERB_SET_GPIO_MASK, gpiomask);
8321 snd_hda_codec_write(codec, codec->afg, 0,
8322 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8323
8324 msleep(1);
8325
8326 snd_hda_codec_write(codec, codec->afg, 0,
8327 AC_VERB_SET_GPIO_DATA, gpiostate);
8328}
8329
Takashi Iwai7debbe52007-08-16 15:01:03 +02008330/* set up GPIO at initialization */
8331static void alc885_macpro_init_hook(struct hda_codec *codec)
8332{
8333 alc882_gpio_mute(codec, 0, 0);
8334 alc882_gpio_mute(codec, 1, 0);
8335}
8336
8337/* set up GPIO and update auto-muting at initialization */
8338static void alc885_imac24_init_hook(struct hda_codec *codec)
8339{
8340 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008341 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008342}
8343
Kailang Yangdf694da2005-12-05 19:42:22 +01008344/*
8345 * generic initialization of ADC, input mixers and output mixers
8346 */
Takashi Iwai49535502009-06-30 15:28:30 +02008347static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008348 /*
8349 * Unmute ADC0-2 and set the default input to mic-in
8350 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008351 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8352 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8353 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8354 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8355
Kailang Yangdf694da2005-12-05 19:42:22 +01008356 /*
8357 * Set up output mixers (0x0c - 0x0f)
8358 */
8359 /* set vol=0 to output mixers */
8360 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8361 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8362 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8363 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8364 /* set up input amps for analog loopback */
8365 /* Amp Indices: DAC = 0, mixer = 1 */
8366 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8367 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8368 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8369 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8370 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8371 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8372 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8373 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8374 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8375 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8376
8377 /* FIXME: use matrix-type input source selection */
8378 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008379 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008381 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008382 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008383 { }
8384};
8385
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008386/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8387static struct hda_verb alc889A_mb31_ch2_init[] = {
8388 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8389 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8390 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8391 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8392 { } /* end */
8393};
8394
8395/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8396static struct hda_verb alc889A_mb31_ch4_init[] = {
8397 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8398 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8399 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8400 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8401 { } /* end */
8402};
8403
8404/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8405static struct hda_verb alc889A_mb31_ch5_init[] = {
8406 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8407 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8408 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8409 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8410 { } /* end */
8411};
8412
8413/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8414static struct hda_verb alc889A_mb31_ch6_init[] = {
8415 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8416 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8417 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8418 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8419 { } /* end */
8420};
8421
8422static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8423 { 2, alc889A_mb31_ch2_init },
8424 { 4, alc889A_mb31_ch4_init },
8425 { 5, alc889A_mb31_ch5_init },
8426 { 6, alc889A_mb31_ch6_init },
8427};
8428
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008429static struct hda_verb alc883_medion_eapd_verbs[] = {
8430 /* eanable EAPD on medion laptop */
8431 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8432 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8433 { }
8434};
8435
Takashi Iwai49535502009-06-30 15:28:30 +02008436#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008437
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008438static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8439 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8440 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8441 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8442 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8443 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8444 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8445 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8446 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8447 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8448 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8449 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8450 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8451 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008452 { } /* end */
8453};
8454
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008455static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008456 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8457 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8458 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8459 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8460 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8461 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8462 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8463 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8464 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8465 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008466 { } /* end */
8467};
8468
Jiang zhefb97dc62008-03-06 11:07:11 +01008469static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8470 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8471 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8472 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8473 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8474 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8475 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8476 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8477 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8478 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8479 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008480 { } /* end */
8481};
8482
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008483static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8484 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8485 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8486 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8487 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8488 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8489 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8490 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8491 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008492 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008493 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8494 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008495 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008496 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008497 { } /* end */
8498};
8499
8500static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8501 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8502 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8503 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8504 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8505 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8506 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8507 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8508 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8509 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8510 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8511 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8512 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8513 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008515 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008516 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8517 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008518 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008519 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008520 { } /* end */
8521};
8522
Jiang zhe17bba1b2008-06-04 12:11:07 +02008523static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8524 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8525 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8526 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8527 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8528 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8529 HDA_OUTPUT),
8530 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8531 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8532 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8533 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8534 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8535 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8536 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8537 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8538 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8539 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8540 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8541 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8542 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8543 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008544 { } /* end */
8545};
8546
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008547static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8548 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8549 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8550 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8551 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8552 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8553 HDA_OUTPUT),
8554 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8555 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8556 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8557 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8558 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8559 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8560 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8561 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8562 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8563 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8564 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8565 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8566 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8567 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8568 { } /* end */
8569};
8570
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008571static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008572 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008573 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008574 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008575 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008576 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8577 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008578 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8579 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008580 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8581 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8582 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8583 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8584 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8585 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008586 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008587 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8588 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008589 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008590 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008591 { } /* end */
8592};
8593
Sasha Alexandrc2592492009-06-16 14:52:54 -04008594static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008595 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008596 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008597 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008598 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008599 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8600 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8601 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8602 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8603 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8604 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8605 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8606 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8607 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8608 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8609 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008610 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008611 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008612 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008613};
Kailang Yangccc656c2006-10-17 12:32:26 +02008614
Sasha Alexandrc2592492009-06-16 14:52:54 -04008615static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008616 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008617 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008618 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008619 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008620 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8621 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8622 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008623 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008624 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008625 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8626 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8627 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008628 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008629};
Kailang Yangccc656c2006-10-17 12:32:26 +02008630
Takashi Iwaib99dba32009-09-17 18:23:00 +02008631static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8632 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8633 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8634 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8635 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8636 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8637 { } /* end */
8638};
8639
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008640static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8641 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8642 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008643 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8644 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008645 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8647 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8648 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008649 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008650};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008651
Kailang Yang272a5272007-05-14 11:00:38 +02008652static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8653 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8654 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8655 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8656 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8657 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8658 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8659 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8660 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8661 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008662 { } /* end */
8663};
8664
8665static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8666 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8667 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8668 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8669 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8670 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8671 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8672 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8673 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8674 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008675 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008676};
Kailang Yang272a5272007-05-14 11:00:38 +02008677
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02008678static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
8679 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8680 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8681 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8682 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
8683 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
8684 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
8685 { } /* end */
8686};
8687
8688static struct hda_verb alc883_medion_wim2160_verbs[] = {
8689 /* Unmute front mixer */
8690 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8691 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8692
8693 /* Set speaker pin to front mixer */
8694 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8695
8696 /* Init headphone pin */
8697 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8698 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8699 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8700 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8701
8702 { } /* end */
8703};
8704
8705/* toggle speaker-output according to the hp-jack state */
8706static void alc883_medion_wim2160_setup(struct hda_codec *codec)
8707{
8708 struct alc_spec *spec = codec->spec;
8709
8710 spec->autocfg.hp_pins[0] = 0x1a;
8711 spec->autocfg.speaker_pins[0] = 0x15;
8712}
8713
Tobin Davis2880a862007-08-07 11:50:26 +02008714static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008715 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8716 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008717 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008718 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8719 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008720 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8721 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8722 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008723 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008724};
Tobin Davis2880a862007-08-07 11:50:26 +02008725
Tony Vroond2fd4b02009-06-21 00:40:10 +01008726static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8727 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008728 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008729 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8730 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008731 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8732 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8733 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8734 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8735 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8736 { } /* end */
8737};
8738
Kailang Yange2757d52008-08-26 13:17:46 +02008739static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8740 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8741 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8742 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8743 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8744 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8745 0x0d, 1, 0x0, HDA_OUTPUT),
8746 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8747 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8748 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8749 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8750 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008751 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8752 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8753 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8754 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8755 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8756 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8757 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8758 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8759 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8760 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008761 { } /* end */
8762};
8763
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008764static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8765 /* Output mixers */
8766 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8767 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8768 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8769 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8770 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8771 HDA_OUTPUT),
8772 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8773 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8774 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8775 /* Output switches */
8776 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8777 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8778 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8779 /* Boost mixers */
8780 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8781 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8782 /* Input mixers */
8783 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8784 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8785 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8786 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8787 { } /* end */
8788};
8789
Guido Günther3e1647c2009-06-05 00:47:26 +02008790static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8791 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8792 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8793 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8794 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8795 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8796 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8797 { } /* end */
8798};
8799
Kailang Yange2757d52008-08-26 13:17:46 +02008800static struct hda_bind_ctls alc883_bind_cap_vol = {
8801 .ops = &snd_hda_bind_vol,
8802 .values = {
8803 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8804 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8805 0
8806 },
8807};
8808
8809static struct hda_bind_ctls alc883_bind_cap_switch = {
8810 .ops = &snd_hda_bind_sw,
8811 .values = {
8812 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8813 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8814 0
8815 },
8816};
8817
8818static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8819 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8820 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8822 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8823 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8824 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8825 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8826 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008827 { } /* end */
8828};
8829
8830static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008831 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8832 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8833 {
8834 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8835 /* .name = "Capture Source", */
8836 .name = "Input Source",
8837 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008838 .info = alc_mux_enum_info,
8839 .get = alc_mux_enum_get,
8840 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008841 },
8842 { } /* end */
8843};
8844
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008845static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8846 {
8847 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8848 .name = "Channel Mode",
8849 .info = alc_ch_mode_info,
8850 .get = alc_ch_mode_get,
8851 .put = alc_ch_mode_put,
8852 },
8853 { } /* end */
8854};
8855
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008856/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008857static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008858{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008859 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008860
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008861 spec->autocfg.hp_pins[0] = 0x15;
8862 spec->autocfg.speaker_pins[0] = 0x14;
8863 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008864}
8865
8866/* auto-toggle front mic */
8867/*
8868static void alc883_mitac_mic_automute(struct hda_codec *codec)
8869{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008870 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008871
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008872 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8873}
8874*/
8875
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008876static struct hda_verb alc883_mitac_verbs[] = {
8877 /* HP */
8878 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8879 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8880 /* Subwoofer */
8881 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8882 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8883
8884 /* enable unsolicited event */
8885 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8886 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8887
8888 { } /* end */
8889};
8890
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308891static struct hda_verb alc883_clevo_m540r_verbs[] = {
8892 /* HP */
8893 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8894 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8895 /* Int speaker */
8896 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8897
8898 /* enable unsolicited event */
8899 /*
8900 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8901 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8902 */
8903
8904 { } /* end */
8905};
8906
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008907static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008908 /* HP */
8909 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8910 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8911 /* Int speaker */
8912 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8913 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8914
8915 /* enable unsolicited event */
8916 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008917 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008918
8919 { } /* end */
8920};
8921
Jiang zhefb97dc62008-03-06 11:07:11 +01008922static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8923 /* HP */
8924 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8925 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8926 /* Subwoofer */
8927 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8928 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8929
8930 /* enable unsolicited event */
8931 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8932
8933 { } /* end */
8934};
8935
Sasha Alexandrc2592492009-06-16 14:52:54 -04008936static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008937 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8938 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8939
8940 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8941 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008942
David Heidelberger64a8be72009-06-08 16:15:18 +02008943/* Connect Line-Out side jack (SPDIF) to Side */
8944 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8945 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8946 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8947/* Connect Mic jack to CLFE */
8948 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8949 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8950 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
8951/* Connect Line-in jack to Surround */
8952 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8953 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8954 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8955/* Connect HP out jack to Front */
8956 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8957 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8958 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02008959
8960 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02008961
8962 { } /* end */
8963};
8964
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008965static struct hda_verb alc883_lenovo_101e_verbs[] = {
8966 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8967 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8968 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8969 { } /* end */
8970};
8971
Kailang Yang272a5272007-05-14 11:00:38 +02008972static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8973 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8974 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8975 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8976 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8977 { } /* end */
8978};
8979
8980static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8981 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8982 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8983 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8984 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8985 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8986 { } /* end */
8987};
8988
Kailang Yang189609a2007-08-20 11:31:23 +02008989static struct hda_verb alc883_haier_w66_verbs[] = {
8990 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8991 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8992
8993 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8994
8995 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8996 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8997 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8998 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8999 { } /* end */
9000};
9001
Kailang Yange2757d52008-08-26 13:17:46 +02009002static struct hda_verb alc888_lenovo_sky_verbs[] = {
9003 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9004 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9005 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9006 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9007 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9008 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9009 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9010 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9011 { } /* end */
9012};
9013
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009014static struct hda_verb alc888_6st_dell_verbs[] = {
9015 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9016 { }
9017};
9018
Guido Günther3e1647c2009-06-05 00:47:26 +02009019static struct hda_verb alc883_vaiott_verbs[] = {
9020 /* HP */
9021 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9022 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9023
9024 /* enable unsolicited event */
9025 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9026
9027 { } /* end */
9028};
9029
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009030static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009031{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009032 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009033
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009034 spec->autocfg.hp_pins[0] = 0x1b;
9035 spec->autocfg.speaker_pins[0] = 0x14;
9036 spec->autocfg.speaker_pins[1] = 0x16;
9037 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009038}
9039
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009040static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009041 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009042 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9043 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009044 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009045 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009046};
9047
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009048/*
9049 * 2ch mode
9050 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009051static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009052 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9053 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9054 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9055 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009056 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009057};
9058
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009059/*
9060 * 4ch mode
9061 */
9062static struct hda_verb alc888_3st_hp_4ch_init[] = {
9063 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9064 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9065 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9066 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9067 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9068 { } /* end */
9069};
9070
9071/*
9072 * 6ch mode
9073 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009074static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009075 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9076 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009077 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009078 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9079 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009080 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9081 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009082};
9083
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009084static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009085 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009086 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009087 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009088};
9089
Kailang Yang272a5272007-05-14 11:00:38 +02009090/* toggle front-jack and RCA according to the hp-jack state */
9091static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9092{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009093 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009094
Takashi Iwai47fd8302007-08-10 17:11:07 +02009095 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9096 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9097 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9098 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009099}
9100
9101/* toggle RCA according to the front-jack state */
9102static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9103{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009104 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009105
Takashi Iwai47fd8302007-08-10 17:11:07 +02009106 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9107 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009108}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009109
Kailang Yang272a5272007-05-14 11:00:38 +02009110static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9111 unsigned int res)
9112{
9113 if ((res >> 26) == ALC880_HP_EVENT)
9114 alc888_lenovo_ms7195_front_automute(codec);
9115 if ((res >> 26) == ALC880_FRONT_EVENT)
9116 alc888_lenovo_ms7195_rca_automute(codec);
9117}
9118
9119static struct hda_verb alc883_medion_md2_verbs[] = {
9120 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9121 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9122
9123 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9124
9125 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9126 { } /* end */
9127};
9128
9129/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009130static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009131{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009132 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009133
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009134 spec->autocfg.hp_pins[0] = 0x14;
9135 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009136}
9137
Kailang Yangccc656c2006-10-17 12:32:26 +02009138/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009139#define alc883_targa_init_hook alc882_targa_init_hook
9140#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009141
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009142static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
9143{
9144 unsigned int present;
9145
Takashi Iwaid56757a2009-11-18 08:00:14 +01009146 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009147 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
9148 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9149}
9150
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009151static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009152{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009153 struct alc_spec *spec = codec->spec;
9154
9155 spec->autocfg.hp_pins[0] = 0x15;
9156 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009157}
9158
9159static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9160{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009161 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009162 alc883_clevo_m720_mic_automute(codec);
9163}
9164
9165static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009166 unsigned int res)
9167{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009168 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009169 case ALC880_MIC_EVENT:
9170 alc883_clevo_m720_mic_automute(codec);
9171 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009172 default:
9173 alc_automute_amp_unsol_event(codec, res);
9174 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009175 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009176}
9177
Jiang zhefb97dc62008-03-06 11:07:11 +01009178/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009179static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009180{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009181 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009182
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009183 spec->autocfg.hp_pins[0] = 0x14;
9184 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009185}
9186
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009187static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009188{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009189 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009190
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009191 spec->autocfg.hp_pins[0] = 0x1b;
9192 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009193}
9194
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009195static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9196{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009197 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009198
Takashi Iwai47fd8302007-08-10 17:11:07 +02009199 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9200 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009201}
9202
9203static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9204{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009205 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009206
Takashi Iwai47fd8302007-08-10 17:11:07 +02009207 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9208 HDA_AMP_MUTE, bits);
9209 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9210 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009211}
9212
9213static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9214 unsigned int res)
9215{
9216 if ((res >> 26) == ALC880_HP_EVENT)
9217 alc883_lenovo_101e_all_automute(codec);
9218 if ((res >> 26) == ALC880_FRONT_EVENT)
9219 alc883_lenovo_101e_ispeaker_automute(codec);
9220}
9221
Takashi Iwai676a9b52007-08-16 15:23:35 +02009222/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009223static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009224{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009225 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009226
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009227 spec->autocfg.hp_pins[0] = 0x14;
9228 spec->autocfg.speaker_pins[0] = 0x15;
9229 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009230}
9231
Kailang Yangd1a991a2007-08-15 16:21:59 +02009232static struct hda_verb alc883_acer_eapd_verbs[] = {
9233 /* HP Pin: output 0 (0x0c) */
9234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9237 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009238 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9239 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009240 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009241 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9242 /* eanable EAPD on medion laptop */
9243 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9244 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009245 /* enable unsolicited event */
9246 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009247 { }
9248};
9249
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009250static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
9251 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9252 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9253 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9254 { } /* end */
9255};
9256
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009257static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009258{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009259 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009260
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009261 spec->autocfg.hp_pins[0] = 0x1b;
9262 spec->autocfg.speaker_pins[0] = 0x14;
9263 spec->autocfg.speaker_pins[1] = 0x15;
9264 spec->autocfg.speaker_pins[2] = 0x16;
9265 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009266}
9267
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009268static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009269{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009270 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009271
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009272 spec->autocfg.hp_pins[0] = 0x1b;
9273 spec->autocfg.speaker_pins[0] = 0x14;
9274 spec->autocfg.speaker_pins[1] = 0x15;
9275 spec->autocfg.speaker_pins[2] = 0x16;
9276 spec->autocfg.speaker_pins[3] = 0x17;
9277 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009278}
9279
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009280static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009281{
9282 struct alc_spec *spec = codec->spec;
9283
9284 spec->autocfg.hp_pins[0] = 0x15;
9285 spec->autocfg.speaker_pins[0] = 0x14;
9286 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009287}
9288
Kailang Yange2757d52008-08-26 13:17:46 +02009289static struct hda_verb alc888_asus_m90v_verbs[] = {
9290 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9291 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9292 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9293 /* enable unsolicited event */
9294 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9295 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9296 { } /* end */
9297};
9298
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009299static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009300{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009301 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009302
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009303 spec->autocfg.hp_pins[0] = 0x1b;
9304 spec->autocfg.speaker_pins[0] = 0x14;
9305 spec->autocfg.speaker_pins[1] = 0x15;
9306 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009307 spec->ext_mic.pin = 0x18;
9308 spec->int_mic.pin = 0x19;
9309 spec->ext_mic.mux_idx = 0;
9310 spec->int_mic.mux_idx = 1;
9311 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009312}
9313
9314static struct hda_verb alc888_asus_eee1601_verbs[] = {
9315 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9316 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9317 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9318 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9319 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9320 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9321 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9322 /* enable unsolicited event */
9323 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9324 { } /* end */
9325};
9326
Kailang Yange2757d52008-08-26 13:17:46 +02009327static void alc883_eee1601_inithook(struct hda_codec *codec)
9328{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009329 struct alc_spec *spec = codec->spec;
9330
9331 spec->autocfg.hp_pins[0] = 0x14;
9332 spec->autocfg.speaker_pins[0] = 0x1b;
9333 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009334}
9335
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009336static struct hda_verb alc889A_mb31_verbs[] = {
9337 /* Init rear pin (used as headphone output) */
9338 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9339 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9340 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9341 /* Init line pin (used as output in 4ch and 6ch mode) */
9342 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9343 /* Init line 2 pin (used as headphone out by default) */
9344 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9345 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9346 { } /* end */
9347};
9348
9349/* Mute speakers according to the headphone jack state */
9350static void alc889A_mb31_automute(struct hda_codec *codec)
9351{
9352 unsigned int present;
9353
9354 /* Mute only in 2ch or 4ch mode */
9355 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9356 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009357 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009358 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9359 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9360 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9361 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9362 }
9363}
9364
9365static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9366{
9367 if ((res >> 26) == ALC880_HP_EVENT)
9368 alc889A_mb31_automute(codec);
9369}
9370
Takashi Iwai49535502009-06-30 15:28:30 +02009371
Takashi Iwaicb53c622007-08-10 17:21:45 +02009372#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009373#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009374#endif
9375
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009376/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +02009377#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9378#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9379#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9380#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9381
9382static hda_nid_t alc883_slave_dig_outs[] = {
9383 ALC1200_DIGOUT_NID, 0,
9384};
9385
9386static hda_nid_t alc1200_slave_dig_outs[] = {
9387 ALC883_DIGOUT_NID, 0,
9388};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009389
9390/*
9391 * configuration and preset
9392 */
Takashi Iwai49535502009-06-30 15:28:30 +02009393static const char *alc882_models[ALC882_MODEL_LAST] = {
9394 [ALC882_3ST_DIG] = "3stack-dig",
9395 [ALC882_6ST_DIG] = "6stack-dig",
9396 [ALC882_ARIMA] = "arima",
9397 [ALC882_W2JC] = "w2jc",
9398 [ALC882_TARGA] = "targa",
9399 [ALC882_ASUS_A7J] = "asus-a7j",
9400 [ALC882_ASUS_A7M] = "asus-a7m",
9401 [ALC885_MACPRO] = "macpro",
9402 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009403 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009404 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009405 [ALC885_MBP3] = "mbp3",
9406 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009407 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009408 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009409 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9410 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009411 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009412 [ALC883_TARGA_DIG] = "targa-dig",
9413 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009414 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009415 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009416 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009417 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009418 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009419 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009420 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009421 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009422 [ALC883_MEDION_MD2] = "medion-md2",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009423 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009424 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009425 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009426 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9427 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009428 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009429 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009430 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009431 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009432 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309433 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009434 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009435 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009436 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009437 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009438 [ALC889A_INTEL] = "intel-alc889a",
9439 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009440 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009441 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009442 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009443 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009444};
9445
Takashi Iwai49535502009-06-30 15:28:30 +02009446static struct snd_pci_quirk alc882_cfg_tbl[] = {
9447 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9448
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009449 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009450 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009451 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009452 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9453 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009454 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009455 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9456 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009457 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009458 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009459 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9460 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009461 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9462 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009463 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9464 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009465 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009466 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009467 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009468 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009469 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9470 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009471 /* default Acer -- disabled as it causes more problems.
9472 * model=auto should work fine now
9473 */
9474 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009475
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009476 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009477
Tobin Davisfebe3372007-06-12 11:27:46 +02009478 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009479 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9480 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009481 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009482 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009483 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009484
9485 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9486 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9487 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009488 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009489 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9490 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9491 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009492 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009493 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009494 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009495 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009496
9497 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009498 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009499 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009500 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009501 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9502 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009503 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009504 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009505 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9506
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009507 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9508 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9509 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009510 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009511 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009512 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009513 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009514 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009515 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9516 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9517 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9518 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9519 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9520 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009521 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009522 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9523 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9524 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009525 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009526 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009527 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9528 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009529 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009530 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009531 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009532 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009533 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009534 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009535 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009536 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009537 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009538
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009539 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009540 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009541 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9542 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309543 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009544 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009545 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009546 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009547 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009548 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009549 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009550 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009551 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009552 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009553 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009554 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9555 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009556 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009557 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009558 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009559 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009560 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009561
Jiang zhe17bba1b2008-06-04 12:11:07 +02009562 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9563 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009564 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009565 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9566 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9567 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009568 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009569
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009570 {}
9571};
9572
Takashi Iwai49535502009-06-30 15:28:30 +02009573/* codec SSID table for Intel Mac */
9574static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9575 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9576 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9577 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9578 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9579 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9580 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9581 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009582 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009583 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009584 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009585 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +02009586 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9587 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9588 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009589 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009590 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009591 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009592 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9593 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009594 */
9595 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009596 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009597 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +02009598 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009599};
9600
Takashi Iwai49535502009-06-30 15:28:30 +02009601static struct alc_config_preset alc882_presets[] = {
9602 [ALC882_3ST_DIG] = {
9603 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009604 .init_verbs = { alc882_base_init_verbs,
9605 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009606 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9607 .dac_nids = alc882_dac_nids,
9608 .dig_out_nid = ALC882_DIGOUT_NID,
9609 .dig_in_nid = ALC882_DIGIN_NID,
9610 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9611 .channel_mode = alc882_ch_modes,
9612 .need_dac_fix = 1,
9613 .input_mux = &alc882_capture_source,
9614 },
9615 [ALC882_6ST_DIG] = {
9616 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009617 .init_verbs = { alc882_base_init_verbs,
9618 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009619 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9620 .dac_nids = alc882_dac_nids,
9621 .dig_out_nid = ALC882_DIGOUT_NID,
9622 .dig_in_nid = ALC882_DIGIN_NID,
9623 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9624 .channel_mode = alc882_sixstack_modes,
9625 .input_mux = &alc882_capture_source,
9626 },
9627 [ALC882_ARIMA] = {
9628 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009629 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9630 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009631 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9632 .dac_nids = alc882_dac_nids,
9633 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9634 .channel_mode = alc882_sixstack_modes,
9635 .input_mux = &alc882_capture_source,
9636 },
9637 [ALC882_W2JC] = {
9638 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009639 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9640 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009641 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9642 .dac_nids = alc882_dac_nids,
9643 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9644 .channel_mode = alc880_threestack_modes,
9645 .need_dac_fix = 1,
9646 .input_mux = &alc882_capture_source,
9647 .dig_out_nid = ALC882_DIGOUT_NID,
9648 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009649 [ALC885_MBA21] = {
9650 .mixers = { alc885_mba21_mixer },
9651 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9652 .num_dacs = 2,
9653 .dac_nids = alc882_dac_nids,
9654 .channel_mode = alc885_mba21_ch_modes,
9655 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9656 .input_mux = &alc882_capture_source,
9657 .unsol_event = alc_automute_amp_unsol_event,
9658 .setup = alc885_mba21_setup,
9659 .init_hook = alc_automute_amp,
9660 },
Takashi Iwai49535502009-06-30 15:28:30 +02009661 [ALC885_MBP3] = {
9662 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9663 .init_verbs = { alc885_mbp3_init_verbs,
9664 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009665 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +02009666 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009667 .hp_nid = 0x04,
9668 .channel_mode = alc885_mbp_4ch_modes,
9669 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +02009670 .input_mux = &alc882_capture_source,
9671 .dig_out_nid = ALC882_DIGOUT_NID,
9672 .dig_in_nid = ALC882_DIGIN_NID,
9673 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009674 .setup = alc885_mbp3_setup,
9675 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009676 },
9677 [ALC885_MB5] = {
9678 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9679 .init_verbs = { alc885_mb5_init_verbs,
9680 alc880_gpio1_init_verbs },
9681 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9682 .dac_nids = alc882_dac_nids,
9683 .channel_mode = alc885_mb5_6ch_modes,
9684 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9685 .input_mux = &mb5_capture_source,
9686 .dig_out_nid = ALC882_DIGOUT_NID,
9687 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009688 .unsol_event = alc_automute_amp_unsol_event,
9689 .setup = alc885_mb5_setup,
9690 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009691 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009692 [ALC885_MACMINI3] = {
9693 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9694 .init_verbs = { alc885_macmini3_init_verbs,
9695 alc880_gpio1_init_verbs },
9696 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9697 .dac_nids = alc882_dac_nids,
9698 .channel_mode = alc885_macmini3_6ch_modes,
9699 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9700 .input_mux = &macmini3_capture_source,
9701 .dig_out_nid = ALC882_DIGOUT_NID,
9702 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009703 .unsol_event = alc_automute_amp_unsol_event,
9704 .setup = alc885_macmini3_setup,
9705 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009706 },
Takashi Iwai49535502009-06-30 15:28:30 +02009707 [ALC885_MACPRO] = {
9708 .mixers = { alc882_macpro_mixer },
9709 .init_verbs = { alc882_macpro_init_verbs },
9710 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9711 .dac_nids = alc882_dac_nids,
9712 .dig_out_nid = ALC882_DIGOUT_NID,
9713 .dig_in_nid = ALC882_DIGIN_NID,
9714 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9715 .channel_mode = alc882_ch_modes,
9716 .input_mux = &alc882_capture_source,
9717 .init_hook = alc885_macpro_init_hook,
9718 },
9719 [ALC885_IMAC24] = {
9720 .mixers = { alc885_imac24_mixer },
9721 .init_verbs = { alc885_imac24_init_verbs },
9722 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9723 .dac_nids = alc882_dac_nids,
9724 .dig_out_nid = ALC882_DIGOUT_NID,
9725 .dig_in_nid = ALC882_DIGIN_NID,
9726 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9727 .channel_mode = alc882_ch_modes,
9728 .input_mux = &alc882_capture_source,
9729 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009730 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +02009731 .init_hook = alc885_imac24_init_hook,
9732 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009733 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009734 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009735 .init_verbs = { alc885_imac91_init_verbs,
9736 alc880_gpio1_init_verbs },
9737 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9738 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009739 .channel_mode = alc885_mba21_ch_modes,
9740 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9741 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009742 .dig_out_nid = ALC882_DIGOUT_NID,
9743 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009744 .unsol_event = alc_automute_amp_unsol_event,
9745 .setup = alc885_imac91_setup,
9746 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009747 },
Takashi Iwai49535502009-06-30 15:28:30 +02009748 [ALC882_TARGA] = {
9749 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009750 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009751 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009752 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9753 .dac_nids = alc882_dac_nids,
9754 .dig_out_nid = ALC882_DIGOUT_NID,
9755 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9756 .adc_nids = alc882_adc_nids,
9757 .capsrc_nids = alc882_capsrc_nids,
9758 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9759 .channel_mode = alc882_3ST_6ch_modes,
9760 .need_dac_fix = 1,
9761 .input_mux = &alc882_capture_source,
9762 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009763 .setup = alc882_targa_setup,
9764 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +02009765 },
9766 [ALC882_ASUS_A7J] = {
9767 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009768 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9769 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009770 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9771 .dac_nids = alc882_dac_nids,
9772 .dig_out_nid = ALC882_DIGOUT_NID,
9773 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9774 .adc_nids = alc882_adc_nids,
9775 .capsrc_nids = alc882_capsrc_nids,
9776 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9777 .channel_mode = alc882_3ST_6ch_modes,
9778 .need_dac_fix = 1,
9779 .input_mux = &alc882_capture_source,
9780 },
9781 [ALC882_ASUS_A7M] = {
9782 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009783 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9784 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +02009785 alc882_asus_a7m_verbs },
9786 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9787 .dac_nids = alc882_dac_nids,
9788 .dig_out_nid = ALC882_DIGOUT_NID,
9789 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9790 .channel_mode = alc880_threestack_modes,
9791 .need_dac_fix = 1,
9792 .input_mux = &alc882_capture_source,
9793 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009794 [ALC883_3ST_2ch_DIG] = {
9795 .mixers = { alc883_3ST_2ch_mixer },
9796 .init_verbs = { alc883_init_verbs },
9797 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9798 .dac_nids = alc883_dac_nids,
9799 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009800 .dig_in_nid = ALC883_DIGIN_NID,
9801 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9802 .channel_mode = alc883_3ST_2ch_modes,
9803 .input_mux = &alc883_capture_source,
9804 },
9805 [ALC883_3ST_6ch_DIG] = {
9806 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9807 .init_verbs = { alc883_init_verbs },
9808 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9809 .dac_nids = alc883_dac_nids,
9810 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009811 .dig_in_nid = ALC883_DIGIN_NID,
9812 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9813 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009814 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009815 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009816 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009817 [ALC883_3ST_6ch] = {
9818 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9819 .init_verbs = { alc883_init_verbs },
9820 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9821 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009822 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9823 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009824 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009825 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009826 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009827 [ALC883_3ST_6ch_INTEL] = {
9828 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9829 .init_verbs = { alc883_init_verbs },
9830 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9831 .dac_nids = alc883_dac_nids,
9832 .dig_out_nid = ALC883_DIGOUT_NID,
9833 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009834 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009835 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9836 .channel_mode = alc883_3ST_6ch_intel_modes,
9837 .need_dac_fix = 1,
9838 .input_mux = &alc883_3stack_6ch_intel,
9839 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009840 [ALC889A_INTEL] = {
9841 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009842 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9843 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009844 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9845 .dac_nids = alc883_dac_nids,
9846 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9847 .adc_nids = alc889_adc_nids,
9848 .dig_out_nid = ALC883_DIGOUT_NID,
9849 .dig_in_nid = ALC883_DIGIN_NID,
9850 .slave_dig_outs = alc883_slave_dig_outs,
9851 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9852 .channel_mode = alc889_8ch_intel_modes,
9853 .capsrc_nids = alc889_capsrc_nids,
9854 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009855 .setup = alc889_automute_setup,
9856 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009857 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009858 .need_dac_fix = 1,
9859 },
9860 [ALC889_INTEL] = {
9861 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9862 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009863 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009864 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9865 .dac_nids = alc883_dac_nids,
9866 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9867 .adc_nids = alc889_adc_nids,
9868 .dig_out_nid = ALC883_DIGOUT_NID,
9869 .dig_in_nid = ALC883_DIGIN_NID,
9870 .slave_dig_outs = alc883_slave_dig_outs,
9871 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9872 .channel_mode = alc889_8ch_intel_modes,
9873 .capsrc_nids = alc889_capsrc_nids,
9874 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009875 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009876 .init_hook = alc889_intel_init_hook,
9877 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009878 .need_dac_fix = 1,
9879 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009880 [ALC883_6ST_DIG] = {
9881 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9882 .init_verbs = { alc883_init_verbs },
9883 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9884 .dac_nids = alc883_dac_nids,
9885 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009886 .dig_in_nid = ALC883_DIGIN_NID,
9887 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9888 .channel_mode = alc883_sixstack_modes,
9889 .input_mux = &alc883_capture_source,
9890 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009891 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009892 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009893 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9894 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009895 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9896 .dac_nids = alc883_dac_nids,
9897 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009898 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9899 .channel_mode = alc883_3ST_6ch_modes,
9900 .need_dac_fix = 1,
9901 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009902 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009903 .setup = alc882_targa_setup,
9904 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009905 },
9906 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009907 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009908 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9909 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009910 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9911 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009912 .adc_nids = alc883_adc_nids_alt,
9913 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009914 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +02009915 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009916 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9917 .channel_mode = alc883_3ST_2ch_modes,
9918 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009919 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009920 .setup = alc882_targa_setup,
9921 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009922 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009923 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009924 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9925 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009926 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009927 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009928 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9929 .dac_nids = alc883_dac_nids,
9930 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9931 .adc_nids = alc883_adc_nids_rev,
9932 .capsrc_nids = alc883_capsrc_nids_rev,
9933 .dig_out_nid = ALC883_DIGOUT_NID,
9934 .dig_in_nid = ALC883_DIGIN_NID,
9935 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
9936 .channel_mode = alc883_4ST_8ch_modes,
9937 .need_dac_fix = 1,
9938 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009939 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009940 .setup = alc882_targa_setup,
9941 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +02009942 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009943 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009944 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009945 /* On TravelMate laptops, GPIO 0 enables the internal speaker
9946 * and the headphone jack. Turn this on and rely on the
9947 * standard mute methods whenever the user wants to turn
9948 * these outputs off.
9949 */
9950 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
9951 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9952 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009953 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9954 .channel_mode = alc883_3ST_2ch_modes,
9955 .input_mux = &alc883_capture_source,
9956 },
Tobin Davis2880a862007-08-07 11:50:26 +02009957 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009958 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009959 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02009960 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9961 .dac_nids = alc883_dac_nids,
9962 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02009963 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9964 .channel_mode = alc883_3ST_2ch_modes,
9965 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009966 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009967 .setup = alc883_acer_aspire_setup,
9968 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009969 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009970 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009971 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009972 alc883_chmode_mixer },
9973 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9974 alc888_acer_aspire_4930g_verbs },
9975 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9976 .dac_nids = alc883_dac_nids,
9977 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9978 .adc_nids = alc883_adc_nids_rev,
9979 .capsrc_nids = alc883_capsrc_nids_rev,
9980 .dig_out_nid = ALC883_DIGOUT_NID,
9981 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9982 .channel_mode = alc883_3ST_6ch_modes,
9983 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +01009984 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009985 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009986 ARRAY_SIZE(alc888_2_capture_sources),
9987 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009988 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009989 .setup = alc888_acer_aspire_4930g_setup,
9990 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009991 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01009992 [ALC888_ACER_ASPIRE_6530G] = {
9993 .mixers = { alc888_acer_aspire_6530_mixer },
9994 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9995 alc888_acer_aspire_6530g_verbs },
9996 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9997 .dac_nids = alc883_dac_nids,
9998 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9999 .adc_nids = alc883_adc_nids_rev,
10000 .capsrc_nids = alc883_capsrc_nids_rev,
10001 .dig_out_nid = ALC883_DIGOUT_NID,
10002 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10003 .channel_mode = alc883_3ST_2ch_modes,
10004 .num_mux_defs =
10005 ARRAY_SIZE(alc888_2_capture_sources),
10006 .input_mux = alc888_acer_aspire_6530_sources,
10007 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010008 .setup = alc888_acer_aspire_6530g_setup,
10009 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010010 },
Hector Martin3b315d72009-06-02 10:54:19 +020010011 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010012 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010013 alc883_chmode_mixer },
10014 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010015 alc889_acer_aspire_8930g_verbs,
10016 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010017 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10018 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010019 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10020 .adc_nids = alc889_adc_nids,
10021 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010022 .dig_out_nid = ALC883_DIGOUT_NID,
10023 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10024 .channel_mode = alc883_3ST_6ch_modes,
10025 .need_dac_fix = 1,
10026 .const_channel_count = 6,
10027 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010028 ARRAY_SIZE(alc889_capture_sources),
10029 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010030 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010031 .setup = alc889_acer_aspire_8930g_setup,
10032 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010033#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010034 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010035#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010036 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010037 [ALC888_ACER_ASPIRE_7730G] = {
10038 .mixers = { alc883_3ST_6ch_mixer,
10039 alc883_chmode_mixer },
10040 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10041 alc888_acer_aspire_7730G_verbs },
10042 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10043 .dac_nids = alc883_dac_nids,
10044 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10045 .adc_nids = alc883_adc_nids_rev,
10046 .capsrc_nids = alc883_capsrc_nids_rev,
10047 .dig_out_nid = ALC883_DIGOUT_NID,
10048 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10049 .channel_mode = alc883_3ST_6ch_modes,
10050 .need_dac_fix = 1,
10051 .const_channel_count = 6,
10052 .input_mux = &alc883_capture_source,
10053 .unsol_event = alc_automute_amp_unsol_event,
10054 .setup = alc888_acer_aspire_6530g_setup,
10055 .init_hook = alc_automute_amp,
10056 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010057 [ALC883_MEDION] = {
10058 .mixers = { alc883_fivestack_mixer,
10059 alc883_chmode_mixer },
10060 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010061 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010062 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10063 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010064 .adc_nids = alc883_adc_nids_alt,
10065 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010066 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010067 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10068 .channel_mode = alc883_sixstack_modes,
10069 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010070 },
Kailang Yang272a5272007-05-14 11:00:38 +020010071 [ALC883_MEDION_MD2] = {
10072 .mixers = { alc883_medion_md2_mixer},
10073 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
10074 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10075 .dac_nids = alc883_dac_nids,
10076 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010077 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10078 .channel_mode = alc883_3ST_2ch_modes,
10079 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010080 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010081 .setup = alc883_medion_md2_setup,
10082 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020010083 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010084 [ALC883_MEDION_WIM2160] = {
10085 .mixers = { alc883_medion_wim2160_mixer },
10086 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10087 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10088 .dac_nids = alc883_dac_nids,
10089 .dig_out_nid = ALC883_DIGOUT_NID,
10090 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10091 .adc_nids = alc883_adc_nids,
10092 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10093 .channel_mode = alc883_3ST_2ch_modes,
10094 .input_mux = &alc883_capture_source,
10095 .unsol_event = alc_automute_amp_unsol_event,
10096 .setup = alc883_medion_wim2160_setup,
10097 .init_hook = alc_automute_amp,
10098 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010099 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010100 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010101 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10102 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10103 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010104 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10105 .channel_mode = alc883_3ST_2ch_modes,
10106 .input_mux = &alc883_capture_source,
10107 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010108 [ALC883_CLEVO_M540R] = {
10109 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10110 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10111 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10112 .dac_nids = alc883_dac_nids,
10113 .dig_out_nid = ALC883_DIGOUT_NID,
10114 .dig_in_nid = ALC883_DIGIN_NID,
10115 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10116 .channel_mode = alc883_3ST_6ch_clevo_modes,
10117 .need_dac_fix = 1,
10118 .input_mux = &alc883_capture_source,
10119 /* This machine has the hardware HP auto-muting, thus
10120 * we need no software mute via unsol event
10121 */
10122 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010123 [ALC883_CLEVO_M720] = {
10124 .mixers = { alc883_clevo_m720_mixer },
10125 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010126 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10127 .dac_nids = alc883_dac_nids,
10128 .dig_out_nid = ALC883_DIGOUT_NID,
10129 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10130 .channel_mode = alc883_3ST_2ch_modes,
10131 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010132 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010133 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010134 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010135 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010136 [ALC883_LENOVO_101E_2ch] = {
10137 .mixers = { alc883_lenovo_101e_2ch_mixer},
10138 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10139 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10140 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010141 .adc_nids = alc883_adc_nids_alt,
10142 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010143 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010144 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10145 .channel_mode = alc883_3ST_2ch_modes,
10146 .input_mux = &alc883_lenovo_101e_capture_source,
10147 .unsol_event = alc883_lenovo_101e_unsol_event,
10148 .init_hook = alc883_lenovo_101e_all_automute,
10149 },
Kailang Yang272a5272007-05-14 11:00:38 +020010150 [ALC883_LENOVO_NB0763] = {
10151 .mixers = { alc883_lenovo_nb0763_mixer },
10152 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10153 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10154 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010155 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10156 .channel_mode = alc883_3ST_2ch_modes,
10157 .need_dac_fix = 1,
10158 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010159 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010160 .setup = alc883_medion_md2_setup,
10161 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010162 },
10163 [ALC888_LENOVO_MS7195_DIG] = {
10164 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10165 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10166 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10167 .dac_nids = alc883_dac_nids,
10168 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010169 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10170 .channel_mode = alc883_3ST_6ch_modes,
10171 .need_dac_fix = 1,
10172 .input_mux = &alc883_capture_source,
10173 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10174 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010175 },
10176 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010177 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010178 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10179 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10180 .dac_nids = alc883_dac_nids,
10181 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010182 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10183 .channel_mode = alc883_3ST_2ch_modes,
10184 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010185 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010186 .setup = alc883_haier_w66_setup,
10187 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010188 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010189 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010190 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010191 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010192 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10193 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010194 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10195 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010196 .need_dac_fix = 1,
10197 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010198 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010199 .setup = alc888_3st_hp_setup,
10200 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010201 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010202 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010203 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010204 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10205 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10206 .dac_nids = alc883_dac_nids,
10207 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010208 .dig_in_nid = ALC883_DIGIN_NID,
10209 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10210 .channel_mode = alc883_sixstack_modes,
10211 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010212 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010213 .setup = alc888_6st_dell_setup,
10214 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010215 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010216 [ALC883_MITAC] = {
10217 .mixers = { alc883_mitac_mixer },
10218 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10219 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10220 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010221 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10222 .channel_mode = alc883_3ST_2ch_modes,
10223 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010224 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010225 .setup = alc883_mitac_setup,
10226 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010227 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010228 [ALC883_FUJITSU_PI2515] = {
10229 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10230 .init_verbs = { alc883_init_verbs,
10231 alc883_2ch_fujitsu_pi2515_verbs},
10232 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10233 .dac_nids = alc883_dac_nids,
10234 .dig_out_nid = ALC883_DIGOUT_NID,
10235 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10236 .channel_mode = alc883_3ST_2ch_modes,
10237 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010238 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010239 .setup = alc883_2ch_fujitsu_pi2515_setup,
10240 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010241 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010242 [ALC888_FUJITSU_XA3530] = {
10243 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10244 .init_verbs = { alc883_init_verbs,
10245 alc888_fujitsu_xa3530_verbs },
10246 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10247 .dac_nids = alc883_dac_nids,
10248 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10249 .adc_nids = alc883_adc_nids_rev,
10250 .capsrc_nids = alc883_capsrc_nids_rev,
10251 .dig_out_nid = ALC883_DIGOUT_NID,
10252 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10253 .channel_mode = alc888_4ST_8ch_intel_modes,
10254 .num_mux_defs =
10255 ARRAY_SIZE(alc888_2_capture_sources),
10256 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010257 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010258 .setup = alc888_fujitsu_xa3530_setup,
10259 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010260 },
Kailang Yange2757d52008-08-26 13:17:46 +020010261 [ALC888_LENOVO_SKY] = {
10262 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10263 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10264 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10265 .dac_nids = alc883_dac_nids,
10266 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010267 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10268 .channel_mode = alc883_sixstack_modes,
10269 .need_dac_fix = 1,
10270 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010271 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010272 .setup = alc888_lenovo_sky_setup,
10273 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010274 },
10275 [ALC888_ASUS_M90V] = {
10276 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10277 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10278 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10279 .dac_nids = alc883_dac_nids,
10280 .dig_out_nid = ALC883_DIGOUT_NID,
10281 .dig_in_nid = ALC883_DIGIN_NID,
10282 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10283 .channel_mode = alc883_3ST_6ch_modes,
10284 .need_dac_fix = 1,
10285 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010286 .unsol_event = alc_sku_unsol_event,
10287 .setup = alc883_mode2_setup,
10288 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010289 },
10290 [ALC888_ASUS_EEE1601] = {
10291 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010292 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010293 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10294 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10295 .dac_nids = alc883_dac_nids,
10296 .dig_out_nid = ALC883_DIGOUT_NID,
10297 .dig_in_nid = ALC883_DIGIN_NID,
10298 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10299 .channel_mode = alc883_3ST_2ch_modes,
10300 .need_dac_fix = 1,
10301 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010302 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010303 .init_hook = alc883_eee1601_inithook,
10304 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010305 [ALC1200_ASUS_P5Q] = {
10306 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10307 .init_verbs = { alc883_init_verbs },
10308 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10309 .dac_nids = alc883_dac_nids,
10310 .dig_out_nid = ALC1200_DIGOUT_NID,
10311 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010312 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010313 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10314 .channel_mode = alc883_sixstack_modes,
10315 .input_mux = &alc883_capture_source,
10316 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010317 [ALC889A_MB31] = {
10318 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10319 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10320 alc880_gpio1_init_verbs },
10321 .adc_nids = alc883_adc_nids,
10322 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010323 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010324 .dac_nids = alc883_dac_nids,
10325 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10326 .channel_mode = alc889A_mb31_6ch_modes,
10327 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10328 .input_mux = &alc889A_mb31_capture_source,
10329 .dig_out_nid = ALC883_DIGOUT_NID,
10330 .unsol_event = alc889A_mb31_unsol_event,
10331 .init_hook = alc889A_mb31_automute,
10332 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010333 [ALC883_SONY_VAIO_TT] = {
10334 .mixers = { alc883_vaiott_mixer },
10335 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10336 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10337 .dac_nids = alc883_dac_nids,
10338 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10339 .channel_mode = alc883_3ST_2ch_modes,
10340 .input_mux = &alc883_capture_source,
10341 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010342 .setup = alc883_vaiott_setup,
10343 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010344 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010345};
10346
10347
10348/*
Takashi Iwai49535502009-06-30 15:28:30 +020010349 * Pin config fixes
10350 */
10351enum {
10352 PINFIX_ABIT_AW9D_MAX
10353};
10354
10355static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
10356 { 0x15, 0x01080104 }, /* side */
10357 { 0x16, 0x01011012 }, /* rear */
10358 { 0x17, 0x01016011 }, /* clfe */
10359 { }
10360};
10361
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010362static const struct alc_fixup alc882_fixups[] = {
10363 [PINFIX_ABIT_AW9D_MAX] = {
10364 .pins = alc882_abit_aw9d_pinfix
10365 },
Takashi Iwai49535502009-06-30 15:28:30 +020010366};
10367
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010368static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010369 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
10370 {}
10371};
10372
10373/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010374 * BIOS auto configuration
10375 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010376static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10377 const struct auto_pin_cfg *cfg)
10378{
10379 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10380}
10381
Takashi Iwai49535502009-06-30 15:28:30 +020010382static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010383 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010384 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010385{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010386 int idx;
10387
Takashi Iwai489008c2010-04-07 09:06:00 +020010388 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010389 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010390
Takashi Iwai489008c2010-04-07 09:06:00 +020010391 if (dac == 0x25)
10392 idx = 4;
10393 else if (dac >= 0x02 && dac <= 0x05)
10394 idx = dac - 2;
10395 else
10396 return;
10397 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010398}
10399
Takashi Iwai49535502009-06-30 15:28:30 +020010400static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010401{
10402 struct alc_spec *spec = codec->spec;
10403 int i;
10404
10405 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010406 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010407 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010408 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020010409 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010410 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010411 }
10412}
10413
Takashi Iwai49535502009-06-30 15:28:30 +020010414static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010415{
10416 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010417 hda_nid_t pin, dac;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010418
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010419 pin = spec->autocfg.hp_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010420 if (pin) {
10421 dac = spec->multiout.hp_nid;
10422 if (!dac)
10423 dac = spec->multiout.dac_nids[0]; /* to front */
10424 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10425 }
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010426 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010427 if (pin) {
10428 dac = spec->multiout.extra_out_nid[0];
10429 if (!dac)
10430 dac = spec->multiout.dac_nids[0]; /* to front */
10431 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10432 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010433}
10434
Takashi Iwai49535502009-06-30 15:28:30 +020010435static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010436{
10437 struct alc_spec *spec = codec->spec;
10438 int i;
10439
10440 for (i = 0; i < AUTO_PIN_LAST; i++) {
10441 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai49535502009-06-30 15:28:30 +020010442 if (!nid)
10443 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +020010444 alc_set_input_pin(codec, nid, i);
Takashi Iwai49535502009-06-30 15:28:30 +020010445 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10446 snd_hda_codec_write(codec, nid, 0,
10447 AC_VERB_SET_AMP_GAIN_MUTE,
10448 AMP_OUT_MUTE);
10449 }
10450}
10451
10452static void alc882_auto_init_input_src(struct hda_codec *codec)
10453{
10454 struct alc_spec *spec = codec->spec;
10455 int c;
10456
10457 for (c = 0; c < spec->num_adc_nids; c++) {
10458 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10459 hda_nid_t nid = spec->capsrc_nids[c];
10460 unsigned int mux_idx;
10461 const struct hda_input_mux *imux;
10462 int conns, mute, idx, item;
10463
10464 conns = snd_hda_get_connections(codec, nid, conn_list,
10465 ARRAY_SIZE(conn_list));
10466 if (conns < 0)
10467 continue;
10468 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10469 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010470 if (!imux->num_items && mux_idx > 0)
10471 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020010472 for (idx = 0; idx < conns; idx++) {
10473 /* if the current connection is the selected one,
10474 * unmute it as default - otherwise mute it
10475 */
10476 mute = AMP_IN_MUTE(idx);
10477 for (item = 0; item < imux->num_items; item++) {
10478 if (imux->items[item].index == idx) {
10479 if (spec->cur_mux[c] == item)
10480 mute = AMP_IN_UNMUTE(idx);
10481 break;
10482 }
10483 }
10484 /* check if we have a selector or mixer
10485 * we could check for the widget type instead, but
10486 * just check for Amp-In presence (in case of mixer
10487 * without amp-in there is something wrong, this
10488 * function shouldn't be used or capsrc nid is wrong)
10489 */
10490 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010491 snd_hda_codec_write(codec, nid, 0,
10492 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020010493 mute);
10494 else if (mute != AMP_IN_MUTE(idx))
10495 snd_hda_codec_write(codec, nid, 0,
10496 AC_VERB_SET_CONNECT_SEL,
10497 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010498 }
10499 }
10500}
10501
Takashi Iwai49535502009-06-30 15:28:30 +020010502/* add mic boosts if needed */
10503static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010504{
10505 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010506 int err;
10507 hda_nid_t nid;
10508
10509 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
10510 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10511 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10512 "Mic Boost",
10513 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10514 if (err < 0)
10515 return err;
10516 }
10517 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
10518 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10519 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10520 "Front Mic Boost",
10521 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10522 if (err < 0)
10523 return err;
10524 }
10525 return 0;
10526}
10527
10528/* almost identical with ALC880 parser... */
10529static int alc882_parse_auto_config(struct hda_codec *codec)
10530{
10531 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010532 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
10533 int i, err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010534
Takashi Iwai05f5f472009-08-25 13:10:18 +020010535 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10536 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010537 if (err < 0)
10538 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010539 if (!spec->autocfg.line_outs)
10540 return 0; /* can't find valid BIOS pin config */
10541
10542 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10543 if (err < 0)
10544 return err;
10545 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10546 if (err < 0)
10547 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010548 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10549 "Headphone");
10550 if (err < 0)
10551 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010552 err = alc880_auto_create_extra_out(spec,
10553 spec->autocfg.speaker_pins[0],
10554 "Speaker");
10555 if (err < 0)
10556 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010557 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10558 if (err < 0)
10559 return err;
10560
10561 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10562
10563 /* check multiple SPDIF-out (for recent codecs) */
10564 for (i = 0; i < spec->autocfg.dig_outs; i++) {
10565 hda_nid_t dig_nid;
10566 err = snd_hda_get_connections(codec,
10567 spec->autocfg.dig_out_pins[i],
10568 &dig_nid, 1);
10569 if (err < 0)
10570 continue;
10571 if (!i)
10572 spec->multiout.dig_out_nid = dig_nid;
10573 else {
10574 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010575 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai05f5f472009-08-25 13:10:18 +020010576 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010577 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010578 }
10579 }
10580 if (spec->autocfg.dig_in_pin)
10581 spec->dig_in_nid = ALC880_DIGIN_NID;
10582
10583 if (spec->kctls.list)
10584 add_mixer(spec, spec->kctls.list);
10585
10586 add_verb(spec, alc883_auto_init_verbs);
10587 /* if ADC 0x07 is available, initialize it, too */
10588 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10589 add_verb(spec, alc882_adc1_init_verbs);
10590
10591 spec->num_mux_defs = 1;
10592 spec->input_mux = &spec->private_imux[0];
10593
Kailang Yang6227cdc2010-02-25 08:36:52 +010010594 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010595
10596 err = alc_auto_add_mic_boost(codec);
10597 if (err < 0)
10598 return err;
10599
Takashi Iwai776e1842007-08-29 15:07:11 +020010600 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010601}
10602
10603/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010604static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010605{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010606 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010607 alc882_auto_init_multi_out(codec);
10608 alc882_auto_init_hp_out(codec);
10609 alc882_auto_init_analog_input(codec);
10610 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010611 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010612 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010613}
10614
Takashi Iwai49535502009-06-30 15:28:30 +020010615static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010616{
10617 struct alc_spec *spec;
10618 int err, board_config;
10619
10620 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10621 if (spec == NULL)
10622 return -ENOMEM;
10623
10624 codec->spec = spec;
10625
Kailang Yangda00c242010-03-19 11:23:45 +010010626 alc_auto_parse_customize_define(codec);
10627
Takashi Iwai49535502009-06-30 15:28:30 +020010628 switch (codec->vendor_id) {
10629 case 0x10ec0882:
10630 case 0x10ec0885:
10631 break;
10632 default:
10633 /* ALC883 and variants */
10634 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10635 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010636 }
10637
Takashi Iwai49535502009-06-30 15:28:30 +020010638 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10639 alc882_models,
10640 alc882_cfg_tbl);
10641
10642 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10643 board_config = snd_hda_check_board_codec_sid_config(codec,
10644 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10645
10646 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010647 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010648 codec->chip_name);
10649 board_config = ALC882_AUTO;
10650 }
10651
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010652 if (board_config == ALC882_AUTO)
10653 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai49535502009-06-30 15:28:30 +020010654
10655 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010656 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020010657 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010658 if (err < 0) {
10659 alc_free(codec);
10660 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010661 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010662 printk(KERN_INFO
10663 "hda_codec: Cannot set up configuration "
10664 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020010665 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010666 }
10667 }
10668
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010669 err = snd_hda_attach_beep_device(codec, 0x1);
10670 if (err < 0) {
10671 alc_free(codec);
10672 return err;
10673 }
10674
Takashi Iwai49535502009-06-30 15:28:30 +020010675 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010676 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010677
Takashi Iwai49535502009-06-30 15:28:30 +020010678 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10679 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10680 /* FIXME: setup DAC5 */
10681 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10682 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10683
10684 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10685 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10686
Takashi Iwai49535502009-06-30 15:28:30 +020010687 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010688 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020010689 spec->num_adc_nids = 0;
10690 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010691 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020010692 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010693 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020010694 hda_nid_t nid = alc882_adc_nids[i];
10695 unsigned int wcap = get_wcaps(codec, nid);
10696 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010697 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020010698 if (wcap != AC_WID_AUD_IN)
10699 continue;
10700 spec->private_adc_nids[spec->num_adc_nids] = nid;
10701 err = snd_hda_get_connections(codec, nid, &cap, 1);
10702 if (err < 0)
10703 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010704 err = snd_hda_get_connections(codec, cap, items,
10705 ARRAY_SIZE(items));
10706 if (err < 0)
10707 continue;
10708 for (j = 0; j < imux->num_items; j++)
10709 if (imux->items[j].index >= err)
10710 break;
10711 if (j < imux->num_items)
10712 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020010713 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10714 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010715 }
Takashi Iwai49535502009-06-30 15:28:30 +020010716 spec->adc_nids = spec->private_adc_nids;
10717 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010718 }
10719
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010720 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010010721
10722 if (spec->cdefine.enable_pcbeep)
10723 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010724
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010725 if (board_config == ALC882_AUTO)
10726 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
10727
Takashi Iwai2134ea42008-01-10 16:53:55 +010010728 spec->vmaster_nid = 0x0c;
10729
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010730 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020010731 if (board_config == ALC882_AUTO)
10732 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010733#ifdef CONFIG_SND_HDA_POWER_SAVE
10734 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020010735 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010736#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010737
10738 return 0;
10739}
10740
Takashi Iwai49535502009-06-30 15:28:30 +020010741
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010742/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010743 * ALC262 support
10744 */
10745
10746#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10747#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10748
10749#define alc262_dac_nids alc260_dac_nids
10750#define alc262_adc_nids alc882_adc_nids
10751#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010752#define alc262_capsrc_nids alc882_capsrc_nids
10753#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010754
10755#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010756#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010757
Kailang Yang4e555fe2008-08-26 13:05:55 +020010758static hda_nid_t alc262_dmic_adc_nids[1] = {
10759 /* ADC0 */
10760 0x09
10761};
10762
10763static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10764
Kailang Yangdf694da2005-12-05 19:42:22 +010010765static struct snd_kcontrol_new alc262_base_mixer[] = {
10766 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10767 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10768 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10769 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10770 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10771 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10772 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10773 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010774 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010775 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10776 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010777 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010778 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10779 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10780 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10781 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010782 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010783};
10784
Takashi Iwaice875f02008-01-28 18:17:43 +010010785/* update HP, line and mono-out pins according to the master switch */
10786static void alc262_hp_master_update(struct hda_codec *codec)
10787{
10788 struct alc_spec *spec = codec->spec;
10789 int val = spec->master_sw;
10790
10791 /* HP & line-out */
10792 snd_hda_codec_write_cache(codec, 0x1b, 0,
10793 AC_VERB_SET_PIN_WIDGET_CONTROL,
10794 val ? PIN_HP : 0);
10795 snd_hda_codec_write_cache(codec, 0x15, 0,
10796 AC_VERB_SET_PIN_WIDGET_CONTROL,
10797 val ? PIN_HP : 0);
10798 /* mono (speaker) depending on the HP jack sense */
10799 val = val && !spec->jack_present;
10800 snd_hda_codec_write_cache(codec, 0x16, 0,
10801 AC_VERB_SET_PIN_WIDGET_CONTROL,
10802 val ? PIN_OUT : 0);
10803}
10804
10805static void alc262_hp_bpc_automute(struct hda_codec *codec)
10806{
10807 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010808
10809 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010810 alc262_hp_master_update(codec);
10811}
10812
10813static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10814{
10815 if ((res >> 26) != ALC880_HP_EVENT)
10816 return;
10817 alc262_hp_bpc_automute(codec);
10818}
10819
10820static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10821{
10822 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010823
10824 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010825 alc262_hp_master_update(codec);
10826}
10827
10828static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10829 unsigned int res)
10830{
10831 if ((res >> 26) != ALC880_HP_EVENT)
10832 return;
10833 alc262_hp_wildwest_automute(codec);
10834}
10835
Takashi Iwaib72519b2009-05-08 14:31:55 +020010836#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010837
10838static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10839 struct snd_ctl_elem_value *ucontrol)
10840{
10841 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10842 struct alc_spec *spec = codec->spec;
10843 int val = !!*ucontrol->value.integer.value;
10844
10845 if (val == spec->master_sw)
10846 return 0;
10847 spec->master_sw = val;
10848 alc262_hp_master_update(codec);
10849 return 1;
10850}
10851
Takashi Iwaib72519b2009-05-08 14:31:55 +020010852#define ALC262_HP_MASTER_SWITCH \
10853 { \
10854 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10855 .name = "Master Playback Switch", \
10856 .info = snd_ctl_boolean_mono_info, \
10857 .get = alc262_hp_master_sw_get, \
10858 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010859 }, \
10860 { \
10861 .iface = NID_MAPPING, \
10862 .name = "Master Playback Switch", \
10863 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010864 }
10865
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010866
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010867static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010868 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010869 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10870 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10871 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010872 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10873 HDA_OUTPUT),
10874 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10875 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010876 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10877 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010878 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010879 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10880 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010881 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010882 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10883 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10884 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10885 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010886 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10887 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10888 { } /* end */
10889};
10890
Kailang Yangcd7509a2007-01-26 18:33:17 +010010891static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010892 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010893 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10894 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10895 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10896 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010897 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10898 HDA_OUTPUT),
10899 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10900 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010901 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10902 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010903 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010904 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10905 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10906 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10907 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010908 { } /* end */
10909};
10910
10911static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10912 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10913 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010914 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010915 { } /* end */
10916};
10917
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010918/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010919static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010920{
10921 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010922
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010923 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010010924 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010925}
10926
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010927static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010928 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10929 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010930 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10931 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10932 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10933 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10934 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10935 { } /* end */
10936};
10937
10938static struct hda_verb alc262_hp_t5735_verbs[] = {
10939 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10940 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10941
10942 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10943 { }
10944};
10945
Kailang Yang8c427222008-01-10 13:03:59 +010010946static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010010947 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10948 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010010949 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
10950 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010010951 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10952 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10953 { } /* end */
10954};
10955
10956static struct hda_verb alc262_hp_rp5700_verbs[] = {
10957 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10958 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10959 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10960 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10961 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10962 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10963 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10964 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10965 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10966 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10967 {}
10968};
10969
10970static struct hda_input_mux alc262_hp_rp5700_capture_source = {
10971 .num_items = 1,
10972 .items = {
10973 { "Line", 0x1 },
10974 },
10975};
10976
Takashi Iwai42171c12009-05-08 14:11:43 +020010977/* bind hp and internal speaker mute (with plug check) as master switch */
10978static void alc262_hippo_master_update(struct hda_codec *codec)
10979{
10980 struct alc_spec *spec = codec->spec;
10981 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10982 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10983 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10984 unsigned int mute;
10985
10986 /* HP */
10987 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
10988 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
10989 HDA_AMP_MUTE, mute);
10990 /* mute internal speaker per jack sense */
10991 if (spec->jack_present)
10992 mute = HDA_AMP_MUTE;
10993 if (line_nid)
10994 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
10995 HDA_AMP_MUTE, mute);
10996 if (speaker_nid && speaker_nid != line_nid)
10997 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
10998 HDA_AMP_MUTE, mute);
10999}
11000
11001#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11002
11003static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11004 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011005{
11006 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011007 struct alc_spec *spec = codec->spec;
11008 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011009
Takashi Iwai42171c12009-05-08 14:11:43 +020011010 if (val == spec->master_sw)
11011 return 0;
11012 spec->master_sw = val;
11013 alc262_hippo_master_update(codec);
11014 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011015}
Takashi Iwai5b319542007-07-26 11:49:22 +020011016
Takashi Iwai42171c12009-05-08 14:11:43 +020011017#define ALC262_HIPPO_MASTER_SWITCH \
11018 { \
11019 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11020 .name = "Master Playback Switch", \
11021 .info = snd_ctl_boolean_mono_info, \
11022 .get = alc262_hippo_master_sw_get, \
11023 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011024 }, \
11025 { \
11026 .iface = NID_MAPPING, \
11027 .name = "Master Playback Switch", \
11028 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11029 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011030 }
11031
11032static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11033 ALC262_HIPPO_MASTER_SWITCH,
11034 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11035 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11036 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11037 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11038 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11040 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11041 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11042 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11043 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11044 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11045 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11046 { } /* end */
11047};
11048
11049static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11050 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11051 ALC262_HIPPO_MASTER_SWITCH,
11052 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11053 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11054 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11055 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11056 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11057 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11058 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11059 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11060 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11061 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11062 { } /* end */
11063};
11064
11065/* mute/unmute internal speaker according to the hp jack and mute state */
11066static void alc262_hippo_automute(struct hda_codec *codec)
11067{
11068 struct alc_spec *spec = codec->spec;
11069 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011070
Wu Fengguang864f92b2009-11-18 12:38:02 +080011071 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011072 alc262_hippo_master_update(codec);
11073}
11074
11075static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11076{
11077 if ((res >> 26) != ALC880_HP_EVENT)
11078 return;
11079 alc262_hippo_automute(codec);
11080}
11081
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011082static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011083{
11084 struct alc_spec *spec = codec->spec;
11085
11086 spec->autocfg.hp_pins[0] = 0x15;
11087 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011088}
11089
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011090static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011091{
11092 struct alc_spec *spec = codec->spec;
11093
11094 spec->autocfg.hp_pins[0] = 0x1b;
11095 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011096}
11097
11098
Kailang Yang272a5272007-05-14 11:00:38 +020011099static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011100 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011101 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11104 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11105 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11106 { } /* end */
11107};
11108
Kailang Yang83c34212007-07-05 11:43:05 +020011109static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011110 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11111 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011112 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11113 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11114 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11115 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11116 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11117 { } /* end */
11118};
Kailang Yang272a5272007-05-14 11:00:38 +020011119
Tony Vroonba340e82009-02-02 19:01:30 +000011120static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11121 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11122 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11123 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11124 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11125 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11126 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11128 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11129 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11130 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11131 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11132 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11133 { } /* end */
11134};
11135
11136static struct hda_verb alc262_tyan_verbs[] = {
11137 /* Headphone automute */
11138 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11139 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11140 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11141
11142 /* P11 AUX_IN, white 4-pin connector */
11143 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11144 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11145 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11146 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11147
11148 {}
11149};
11150
11151/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011152static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011153{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011154 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011155
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011156 spec->autocfg.hp_pins[0] = 0x1b;
11157 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011158}
11159
Tony Vroonba340e82009-02-02 19:01:30 +000011160
Kailang Yangdf694da2005-12-05 19:42:22 +010011161#define alc262_capture_mixer alc882_capture_mixer
11162#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11163
11164/*
11165 * generic initialization of ADC, input mixers and output mixers
11166 */
11167static struct hda_verb alc262_init_verbs[] = {
11168 /*
11169 * Unmute ADC0-2 and set the default input to mic-in
11170 */
11171 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11172 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11173 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11174 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11175 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11176 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11177
Takashi Iwaicb53c622007-08-10 17:21:45 +020011178 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011179 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011180 * Note: PASD motherboards uses the Line In 2 as the input for
11181 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011182 */
11183 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011184 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11185 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11186 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11187 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11188 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011189
11190 /*
11191 * Set up output mixers (0x0c - 0x0e)
11192 */
11193 /* set vol=0 to output mixers */
11194 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11195 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11196 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11197 /* set up input amps for analog loopback */
11198 /* Amp Indices: DAC = 0, mixer = 1 */
11199 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11200 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11201 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11202 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11203 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11204 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11205
11206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11207 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11208 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11209 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11210 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11211 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11212
11213 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11214 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11215 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11216 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11217 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011218
Kailang Yangdf694da2005-12-05 19:42:22 +010011219 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11220 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011221
Kailang Yangdf694da2005-12-05 19:42:22 +010011222 /* FIXME: use matrix-type input source selection */
11223 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11224 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11225 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11226 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11227 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11228 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11229 /* Input mixer2 */
11230 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11231 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11232 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11233 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11234 /* Input mixer3 */
11235 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11236 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11237 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011238 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011239
11240 { }
11241};
11242
Kailang Yang4e555fe2008-08-26 13:05:55 +020011243static struct hda_verb alc262_eapd_verbs[] = {
11244 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11245 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11246 { }
11247};
11248
Kailang Yangccc656c2006-10-17 12:32:26 +020011249static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11250 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11251 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11252 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11253
11254 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11255 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11256 {}
11257};
11258
Kailang Yang272a5272007-05-14 11:00:38 +020011259static struct hda_verb alc262_sony_unsol_verbs[] = {
11260 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11261 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11262 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11263
11264 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11265 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011266 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011267};
11268
Kailang Yang4e555fe2008-08-26 13:05:55 +020011269static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11270 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11271 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11272 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11273 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11274 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011275 { } /* end */
11276};
11277
11278static struct hda_verb alc262_toshiba_s06_verbs[] = {
11279 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11280 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11281 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11282 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11283 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11284 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11285 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11286 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11287 {}
11288};
11289
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011290static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011291{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011292 struct alc_spec *spec = codec->spec;
11293
11294 spec->autocfg.hp_pins[0] = 0x15;
11295 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011296 spec->ext_mic.pin = 0x18;
11297 spec->ext_mic.mux_idx = 0;
11298 spec->int_mic.pin = 0x12;
11299 spec->int_mic.mux_idx = 9;
11300 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011301}
11302
Takashi Iwai834be882006-03-01 14:16:17 +010011303/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011304 * nec model
11305 * 0x15 = headphone
11306 * 0x16 = internal speaker
11307 * 0x18 = external mic
11308 */
11309
11310static struct snd_kcontrol_new alc262_nec_mixer[] = {
11311 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11312 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11313
11314 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11315 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11316 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11317
11318 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11319 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11320 { } /* end */
11321};
11322
11323static struct hda_verb alc262_nec_verbs[] = {
11324 /* Unmute Speaker */
11325 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11326
11327 /* Headphone */
11328 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11329 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11330
11331 /* External mic to headphone */
11332 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11333 /* External mic to speaker */
11334 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11335 {}
11336};
11337
11338/*
Takashi Iwai834be882006-03-01 14:16:17 +010011339 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011340 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11341 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011342 */
11343
11344#define ALC_HP_EVENT 0x37
11345
11346static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11347 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11348 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011349 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11350 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011351 {}
11352};
11353
Jiang zhe0e31daf2008-03-20 12:12:39 +010011354static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11355 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11356 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11357 {}
11358};
11359
Daniel T Chene2595322009-12-19 18:19:02 -050011360static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11361 /* Front Mic pin: input vref at 50% */
11362 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11363 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11364 {}
11365};
11366
Takashi Iwai834be882006-03-01 14:16:17 +010011367static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011368 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011369 .items = {
11370 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011371 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011372 { "CD", 0x4 },
11373 },
11374};
11375
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011376static struct hda_input_mux alc262_HP_capture_source = {
11377 .num_items = 5,
11378 .items = {
11379 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011380 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011381 { "Line", 0x2 },
11382 { "CD", 0x4 },
11383 { "AUX IN", 0x6 },
11384 },
11385};
11386
zhejiangaccbe492007-08-31 12:36:05 +020011387static struct hda_input_mux alc262_HP_D7000_capture_source = {
11388 .num_items = 4,
11389 .items = {
11390 { "Mic", 0x0 },
11391 { "Front Mic", 0x2 },
11392 { "Line", 0x1 },
11393 { "CD", 0x4 },
11394 },
11395};
11396
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011397/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011398static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11399{
11400 struct alc_spec *spec = codec->spec;
11401 unsigned int mute;
11402
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011403 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011404 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11405 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011406 spec->sense_updated = 1;
11407 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011408 /* unmute internal speaker only if both HPs are unplugged and
11409 * master switch is on
11410 */
11411 if (spec->jack_present)
11412 mute = HDA_AMP_MUTE;
11413 else
Takashi Iwai834be882006-03-01 14:16:17 +010011414 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011415 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11416 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011417}
11418
11419/* unsolicited event for HP jack sensing */
11420static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11421 unsigned int res)
11422{
11423 if ((res >> 26) != ALC_HP_EVENT)
11424 return;
11425 alc262_fujitsu_automute(codec, 1);
11426}
11427
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011428static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11429{
11430 alc262_fujitsu_automute(codec, 1);
11431}
11432
Takashi Iwai834be882006-03-01 14:16:17 +010011433/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011434static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11435 .ops = &snd_hda_bind_vol,
11436 .values = {
11437 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11438 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11439 0
11440 },
11441};
Takashi Iwai834be882006-03-01 14:16:17 +010011442
Jiang zhe0e31daf2008-03-20 12:12:39 +010011443/* mute/unmute internal speaker according to the hp jack and mute state */
11444static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11445{
11446 struct alc_spec *spec = codec->spec;
11447 unsigned int mute;
11448
11449 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011450 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011451 spec->sense_updated = 1;
11452 }
11453 if (spec->jack_present) {
11454 /* mute internal speaker */
11455 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11456 HDA_AMP_MUTE, HDA_AMP_MUTE);
11457 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11458 HDA_AMP_MUTE, HDA_AMP_MUTE);
11459 } else {
11460 /* unmute internal speaker if necessary */
11461 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11462 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11463 HDA_AMP_MUTE, mute);
11464 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11465 HDA_AMP_MUTE, mute);
11466 }
11467}
11468
11469/* unsolicited event for HP jack sensing */
11470static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11471 unsigned int res)
11472{
11473 if ((res >> 26) != ALC_HP_EVENT)
11474 return;
11475 alc262_lenovo_3000_automute(codec, 1);
11476}
11477
Takashi Iwai8de56b72009-07-24 16:51:47 +020011478static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11479 int dir, int idx, long *valp)
11480{
11481 int i, change = 0;
11482
11483 for (i = 0; i < 2; i++, valp++)
11484 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11485 HDA_AMP_MUTE,
11486 *valp ? 0 : HDA_AMP_MUTE);
11487 return change;
11488}
11489
Takashi Iwai834be882006-03-01 14:16:17 +010011490/* bind hp and internal speaker mute (with plug check) */
11491static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11492 struct snd_ctl_elem_value *ucontrol)
11493{
11494 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11495 long *valp = ucontrol->value.integer.value;
11496 int change;
11497
Takashi Iwai8de56b72009-07-24 16:51:47 +020011498 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11499 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011500 if (change)
11501 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011502 return change;
11503}
11504
11505static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011506 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011507 {
11508 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11509 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011510 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011511 .info = snd_hda_mixer_amp_switch_info,
11512 .get = snd_hda_mixer_amp_switch_get,
11513 .put = alc262_fujitsu_master_sw_put,
11514 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11515 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011516 {
11517 .iface = NID_MAPPING,
11518 .name = "Master Playback Switch",
11519 .private_value = 0x1b,
11520 },
Takashi Iwai834be882006-03-01 14:16:17 +010011521 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11522 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11523 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11524 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11525 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011526 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11527 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11528 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011529 { } /* end */
11530};
11531
Jiang zhe0e31daf2008-03-20 12:12:39 +010011532/* bind hp and internal speaker mute (with plug check) */
11533static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11534 struct snd_ctl_elem_value *ucontrol)
11535{
11536 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11537 long *valp = ucontrol->value.integer.value;
11538 int change;
11539
Takashi Iwai8de56b72009-07-24 16:51:47 +020011540 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011541 if (change)
11542 alc262_lenovo_3000_automute(codec, 0);
11543 return change;
11544}
11545
11546static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11547 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11548 {
11549 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11550 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011551 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011552 .info = snd_hda_mixer_amp_switch_info,
11553 .get = snd_hda_mixer_amp_switch_get,
11554 .put = alc262_lenovo_3000_master_sw_put,
11555 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11556 },
11557 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11558 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11559 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11560 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11561 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11562 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11563 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11564 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11565 { } /* end */
11566};
11567
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011568static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11569 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011570 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011571 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11572 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11573 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11574 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11575 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11576 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11577 { } /* end */
11578};
11579
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011580/* additional init verbs for Benq laptops */
11581static struct hda_verb alc262_EAPD_verbs[] = {
11582 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11583 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11584 {}
11585};
11586
Kailang Yang83c34212007-07-05 11:43:05 +020011587static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11588 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11589 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11590
11591 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11592 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11593 {}
11594};
11595
Tobin Davisf651b502007-10-26 12:40:47 +020011596/* Samsung Q1 Ultra Vista model setup */
11597static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011598 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11599 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011600 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11601 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11602 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011603 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011604 { } /* end */
11605};
11606
11607static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011608 /* output mixer */
11609 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11610 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11611 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11612 /* speaker */
11613 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11614 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11615 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11616 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11617 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011618 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011619 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11620 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11621 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11622 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11623 /* internal mic */
11624 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11625 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11626 /* ADC, choose mic */
11627 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11628 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11629 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11630 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11631 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11632 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11633 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11634 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11635 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11636 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011637 {}
11638};
11639
Tobin Davisf651b502007-10-26 12:40:47 +020011640/* mute/unmute internal speaker according to the hp jack and mute state */
11641static void alc262_ultra_automute(struct hda_codec *codec)
11642{
11643 struct alc_spec *spec = codec->spec;
11644 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011645
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011646 mute = 0;
11647 /* auto-mute only when HP is used as HP */
11648 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011649 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011650 if (spec->jack_present)
11651 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011652 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011653 /* mute/unmute internal speaker */
11654 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11655 HDA_AMP_MUTE, mute);
11656 /* mute/unmute HP */
11657 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11658 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011659}
11660
11661/* unsolicited event for HP jack sensing */
11662static void alc262_ultra_unsol_event(struct hda_codec *codec,
11663 unsigned int res)
11664{
11665 if ((res >> 26) != ALC880_HP_EVENT)
11666 return;
11667 alc262_ultra_automute(codec);
11668}
11669
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011670static struct hda_input_mux alc262_ultra_capture_source = {
11671 .num_items = 2,
11672 .items = {
11673 { "Mic", 0x1 },
11674 { "Headphone", 0x7 },
11675 },
11676};
11677
11678static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11679 struct snd_ctl_elem_value *ucontrol)
11680{
11681 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11682 struct alc_spec *spec = codec->spec;
11683 int ret;
11684
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011685 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011686 if (!ret)
11687 return 0;
11688 /* reprogram the HP pin as mic or HP according to the input source */
11689 snd_hda_codec_write_cache(codec, 0x15, 0,
11690 AC_VERB_SET_PIN_WIDGET_CONTROL,
11691 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11692 alc262_ultra_automute(codec); /* mute/unmute HP */
11693 return ret;
11694}
11695
11696static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11697 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11698 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11699 {
11700 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11701 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011702 .info = alc_mux_enum_info,
11703 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011704 .put = alc262_ultra_mux_enum_put,
11705 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011706 {
11707 .iface = NID_MAPPING,
11708 .name = "Capture Source",
11709 .private_value = 0x15,
11710 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011711 { } /* end */
11712};
11713
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011714/* We use two mixers depending on the output pin; 0x16 is a mono output
11715 * and thus it's bound with a different mixer.
11716 * This function returns which mixer amp should be used.
11717 */
11718static int alc262_check_volbit(hda_nid_t nid)
11719{
11720 if (!nid)
11721 return 0;
11722 else if (nid == 0x16)
11723 return 2;
11724 else
11725 return 1;
11726}
11727
11728static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11729 const char *pfx, int *vbits)
11730{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011731 unsigned long val;
11732 int vbit;
11733
11734 vbit = alc262_check_volbit(nid);
11735 if (!vbit)
11736 return 0;
11737 if (*vbits & vbit) /* a volume control for this mixer already there */
11738 return 0;
11739 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011740 if (vbit == 2)
11741 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11742 else
11743 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011744 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011745}
11746
11747static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11748 const char *pfx)
11749{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011750 unsigned long val;
11751
11752 if (!nid)
11753 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011754 if (nid == 0x16)
11755 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11756 else
11757 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011758 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011759}
11760
Kailang Yangdf694da2005-12-05 19:42:22 +010011761/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011762static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11763 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011764{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011765 const char *pfx;
11766 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011767 int err;
11768
11769 spec->multiout.num_dacs = 1; /* only use one dac */
11770 spec->multiout.dac_nids = spec->private_dac_nids;
11771 spec->multiout.dac_nids[0] = 2;
11772
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011773 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11774 pfx = "Master";
11775 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11776 pfx = "Speaker";
11777 else
11778 pfx = "Front";
11779 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11780 if (err < 0)
11781 return err;
11782 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11783 if (err < 0)
11784 return err;
11785 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11786 if (err < 0)
11787 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011788
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011789 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11790 alc262_check_volbit(cfg->speaker_pins[0]) |
11791 alc262_check_volbit(cfg->hp_pins[0]);
11792 if (vbits == 1 || vbits == 2)
11793 pfx = "Master"; /* only one mixer is used */
11794 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11795 pfx = "Speaker";
11796 else
11797 pfx = "Front";
11798 vbits = 0;
11799 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11800 if (err < 0)
11801 return err;
11802 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11803 &vbits);
11804 if (err < 0)
11805 return err;
11806 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11807 &vbits);
11808 if (err < 0)
11809 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011810 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011811}
11812
Takashi Iwai05f5f472009-08-25 13:10:18 +020011813#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010011814 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011815
11816/*
11817 * generic initialization of ADC, input mixers and output mixers
11818 */
11819static struct hda_verb alc262_volume_init_verbs[] = {
11820 /*
11821 * Unmute ADC0-2 and set the default input to mic-in
11822 */
11823 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11824 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11825 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11826 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11827 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11828 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11829
Takashi Iwaicb53c622007-08-10 17:21:45 +020011830 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011831 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011832 * Note: PASD motherboards uses the Line In 2 as the input for
11833 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011834 */
11835 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011836 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11837 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11838 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11839 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11840 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011841
11842 /*
11843 * Set up output mixers (0x0c - 0x0f)
11844 */
11845 /* set vol=0 to output mixers */
11846 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11847 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11848 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011849
Kailang Yangdf694da2005-12-05 19:42:22 +010011850 /* set up input amps for analog loopback */
11851 /* Amp Indices: DAC = 0, mixer = 1 */
11852 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11853 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11854 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11855 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11856 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11857 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11858
11859 /* FIXME: use matrix-type input source selection */
11860 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11861 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11862 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11863 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11864 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11865 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11866 /* Input mixer2 */
11867 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11868 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11869 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11870 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11871 /* Input mixer3 */
11872 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11873 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11874 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11875 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11876
11877 { }
11878};
11879
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011880static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11881 /*
11882 * Unmute ADC0-2 and set the default input to mic-in
11883 */
11884 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11885 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11886 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11887 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11888 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11889 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11890
Takashi Iwaicb53c622007-08-10 17:21:45 +020011891 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011892 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011893 * Note: PASD motherboards uses the Line In 2 as the input for
11894 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011895 */
11896 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011897 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11898 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11899 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11900 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11901 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11902 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11903 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011904
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011905 /*
11906 * Set up output mixers (0x0c - 0x0e)
11907 */
11908 /* set vol=0 to output mixers */
11909 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11910 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11911 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11912
11913 /* set up input amps for analog loopback */
11914 /* Amp Indices: DAC = 0, mixer = 1 */
11915 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11916 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11917 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11918 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11919 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11920 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11921
Takashi Iwaice875f02008-01-28 18:17:43 +010011922 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011923 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11924 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11925
11926 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11927 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11928
11929 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11930 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11931
11932 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11933 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11934 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11935 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11936 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11937
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011938 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011939 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11940 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011941 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011942 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11943 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11944
11945
11946 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011947 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
11948 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011949 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011950 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11951 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11952 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11953 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11954 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11955 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11956 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11957 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011958 /* Input mixer2 */
11959 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011960 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11961 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11962 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11963 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11964 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11965 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11966 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11967 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011968 /* Input mixer3 */
11969 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011970 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11971 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11972 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11973 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11974 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11975 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11976 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11977 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011978
Takashi Iwaice875f02008-01-28 18:17:43 +010011979 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11980
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011981 { }
11982};
11983
Kailang Yangcd7509a2007-01-26 18:33:17 +010011984static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
11985 /*
11986 * Unmute ADC0-2 and set the default input to mic-in
11987 */
11988 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11989 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11990 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11991 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11992 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11993 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11994
Takashi Iwaicb53c622007-08-10 17:21:45 +020011995 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010011996 * mixer widget
11997 * Note: PASD motherboards uses the Line In 2 as the input for front
11998 * panel mic (mic 2)
11999 */
12000 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012001 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12002 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12003 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12004 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12005 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12006 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12007 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012009 /*
12010 * Set up output mixers (0x0c - 0x0e)
12011 */
12012 /* set vol=0 to output mixers */
12013 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12014 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12015 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12016
12017 /* set up input amps for analog loopback */
12018 /* Amp Indices: DAC = 0, mixer = 1 */
12019 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12020 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12021 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12022 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12023 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12024 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12025
12026
12027 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12028 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12029 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12030 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12031 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12032 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12033 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12034
12035 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12036 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12037
12038 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12039 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12040
12041 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12042 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12043 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12044 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12045 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12046 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12047
12048 /* FIXME: use matrix-type input source selection */
12049 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12050 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12051 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12052 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12053 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12054 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12055 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12056 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12057 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12058 /* Input mixer2 */
12059 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12060 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12061 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12062 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12063 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12064 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12065 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12066 /* Input mixer3 */
12067 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12069 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12070 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12071 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12072 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12073 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12074
Takashi Iwaice875f02008-01-28 18:17:43 +010012075 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12076
Kailang Yangcd7509a2007-01-26 18:33:17 +010012077 { }
12078};
12079
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012080static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12081
12082 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12083 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12084 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12085
12086 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12087 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12088 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12089 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12090
12091 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12092 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12093 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12094 {}
12095};
12096
12097
Takashi Iwaicb53c622007-08-10 17:21:45 +020012098#ifdef CONFIG_SND_HDA_POWER_SAVE
12099#define alc262_loopbacks alc880_loopbacks
12100#endif
12101
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012102/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012103#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12104#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12105#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12106#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12107
12108/*
12109 * BIOS auto configuration
12110 */
12111static int alc262_parse_auto_config(struct hda_codec *codec)
12112{
12113 struct alc_spec *spec = codec->spec;
12114 int err;
12115 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12116
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012117 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12118 alc262_ignore);
12119 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012120 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012121 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012122 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012123 spec->multiout.max_channels = 2;
12124 spec->no_analog = 1;
12125 goto dig_only;
12126 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012127 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012128 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012129 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12130 if (err < 0)
12131 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012132 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012133 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012134 return err;
12135
12136 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12137
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012138 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012139 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010012140 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012141 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012142 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012143 if (spec->autocfg.dig_in_pin)
12144 spec->dig_in_nid = ALC262_DIGIN_NID;
12145
Takashi Iwai603c4012008-07-30 15:01:44 +020012146 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012147 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012148
Takashi Iwaid88897e2008-10-31 15:01:37 +010012149 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012150 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012151 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012152
Takashi Iwai776e1842007-08-29 15:07:11 +020012153 err = alc_auto_add_mic_boost(codec);
12154 if (err < 0)
12155 return err;
12156
Kailang Yang6227cdc2010-02-25 08:36:52 +010012157 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012158
Kailang Yangdf694da2005-12-05 19:42:22 +010012159 return 1;
12160}
12161
12162#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12163#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12164#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012165#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012166
12167
12168/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012169static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012170{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012171 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012172 alc262_auto_init_multi_out(codec);
12173 alc262_auto_init_hp_out(codec);
12174 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012175 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012176 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012177 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012178}
12179
12180/*
12181 * configuration and preset
12182 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012183static const char *alc262_models[ALC262_MODEL_LAST] = {
12184 [ALC262_BASIC] = "basic",
12185 [ALC262_HIPPO] = "hippo",
12186 [ALC262_HIPPO_1] = "hippo_1",
12187 [ALC262_FUJITSU] = "fujitsu",
12188 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012189 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012190 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012191 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012192 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012193 [ALC262_BENQ_T31] = "benq-t31",
12194 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012195 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012196 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012197 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012198 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012199 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012200 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012201 [ALC262_AUTO] = "auto",
12202};
12203
12204static struct snd_pci_quirk alc262_cfg_tbl[] = {
12205 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012206 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012207 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12208 ALC262_HP_BPC),
12209 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12210 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012211 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12212 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012213 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012214 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012215 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012216 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012217 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012218 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012219 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012220 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012221 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12222 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12223 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012224 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12225 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012226 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012227 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012228 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012229 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012230 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012231 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012232 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012233 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012234#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012235 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12236 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012237#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012238 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012239 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012240 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012241 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012242 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012243 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012244 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12245 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012246 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012247 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012248 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012249 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012250 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012251 {}
12252};
12253
12254static struct alc_config_preset alc262_presets[] = {
12255 [ALC262_BASIC] = {
12256 .mixers = { alc262_base_mixer },
12257 .init_verbs = { alc262_init_verbs },
12258 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12259 .dac_nids = alc262_dac_nids,
12260 .hp_nid = 0x03,
12261 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12262 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012263 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012264 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012265 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012266 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012267 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012268 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12269 .dac_nids = alc262_dac_nids,
12270 .hp_nid = 0x03,
12271 .dig_out_nid = ALC262_DIGOUT_NID,
12272 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12273 .channel_mode = alc262_modes,
12274 .input_mux = &alc262_capture_source,
12275 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012276 .setup = alc262_hippo_setup,
12277 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012278 },
12279 [ALC262_HIPPO_1] = {
12280 .mixers = { alc262_hippo1_mixer },
12281 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12282 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12283 .dac_nids = alc262_dac_nids,
12284 .hp_nid = 0x02,
12285 .dig_out_nid = ALC262_DIGOUT_NID,
12286 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12287 .channel_mode = alc262_modes,
12288 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012289 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012290 .setup = alc262_hippo1_setup,
12291 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012292 },
Takashi Iwai834be882006-03-01 14:16:17 +010012293 [ALC262_FUJITSU] = {
12294 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012295 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12296 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012297 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12298 .dac_nids = alc262_dac_nids,
12299 .hp_nid = 0x03,
12300 .dig_out_nid = ALC262_DIGOUT_NID,
12301 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12302 .channel_mode = alc262_modes,
12303 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012304 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012305 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012306 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012307 [ALC262_HP_BPC] = {
12308 .mixers = { alc262_HP_BPC_mixer },
12309 .init_verbs = { alc262_HP_BPC_init_verbs },
12310 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12311 .dac_nids = alc262_dac_nids,
12312 .hp_nid = 0x03,
12313 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12314 .channel_mode = alc262_modes,
12315 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012316 .unsol_event = alc262_hp_bpc_unsol_event,
12317 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012318 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012319 [ALC262_HP_BPC_D7000_WF] = {
12320 .mixers = { alc262_HP_BPC_WildWest_mixer },
12321 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12322 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12323 .dac_nids = alc262_dac_nids,
12324 .hp_nid = 0x03,
12325 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12326 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012327 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012328 .unsol_event = alc262_hp_wildwest_unsol_event,
12329 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012330 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012331 [ALC262_HP_BPC_D7000_WL] = {
12332 .mixers = { alc262_HP_BPC_WildWest_mixer,
12333 alc262_HP_BPC_WildWest_option_mixer },
12334 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12335 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12336 .dac_nids = alc262_dac_nids,
12337 .hp_nid = 0x03,
12338 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12339 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012340 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012341 .unsol_event = alc262_hp_wildwest_unsol_event,
12342 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012343 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012344 [ALC262_HP_TC_T5735] = {
12345 .mixers = { alc262_hp_t5735_mixer },
12346 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12347 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12348 .dac_nids = alc262_dac_nids,
12349 .hp_nid = 0x03,
12350 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12351 .channel_mode = alc262_modes,
12352 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012353 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012354 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012355 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012356 },
12357 [ALC262_HP_RP5700] = {
12358 .mixers = { alc262_hp_rp5700_mixer },
12359 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12360 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12361 .dac_nids = alc262_dac_nids,
12362 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12363 .channel_mode = alc262_modes,
12364 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012365 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012366 [ALC262_BENQ_ED8] = {
12367 .mixers = { alc262_base_mixer },
12368 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12369 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12370 .dac_nids = alc262_dac_nids,
12371 .hp_nid = 0x03,
12372 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12373 .channel_mode = alc262_modes,
12374 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012375 },
Kailang Yang272a5272007-05-14 11:00:38 +020012376 [ALC262_SONY_ASSAMD] = {
12377 .mixers = { alc262_sony_mixer },
12378 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12379 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12380 .dac_nids = alc262_dac_nids,
12381 .hp_nid = 0x02,
12382 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12383 .channel_mode = alc262_modes,
12384 .input_mux = &alc262_capture_source,
12385 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012386 .setup = alc262_hippo_setup,
12387 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012388 },
12389 [ALC262_BENQ_T31] = {
12390 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012391 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12392 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012393 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12394 .dac_nids = alc262_dac_nids,
12395 .hp_nid = 0x03,
12396 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12397 .channel_mode = alc262_modes,
12398 .input_mux = &alc262_capture_source,
12399 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012400 .setup = alc262_hippo_setup,
12401 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012402 },
Tobin Davisf651b502007-10-26 12:40:47 +020012403 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012404 .mixers = { alc262_ultra_mixer },
12405 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012406 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012407 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12408 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012409 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12410 .channel_mode = alc262_modes,
12411 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012412 .adc_nids = alc262_adc_nids, /* ADC0 */
12413 .capsrc_nids = alc262_capsrc_nids,
12414 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012415 .unsol_event = alc262_ultra_unsol_event,
12416 .init_hook = alc262_ultra_automute,
12417 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012418 [ALC262_LENOVO_3000] = {
12419 .mixers = { alc262_lenovo_3000_mixer },
12420 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012421 alc262_lenovo_3000_unsol_verbs,
12422 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012423 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12424 .dac_nids = alc262_dac_nids,
12425 .hp_nid = 0x03,
12426 .dig_out_nid = ALC262_DIGOUT_NID,
12427 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12428 .channel_mode = alc262_modes,
12429 .input_mux = &alc262_fujitsu_capture_source,
12430 .unsol_event = alc262_lenovo_3000_unsol_event,
12431 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012432 [ALC262_NEC] = {
12433 .mixers = { alc262_nec_mixer },
12434 .init_verbs = { alc262_nec_verbs },
12435 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12436 .dac_nids = alc262_dac_nids,
12437 .hp_nid = 0x03,
12438 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12439 .channel_mode = alc262_modes,
12440 .input_mux = &alc262_capture_source,
12441 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012442 [ALC262_TOSHIBA_S06] = {
12443 .mixers = { alc262_toshiba_s06_mixer },
12444 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12445 alc262_eapd_verbs },
12446 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12447 .capsrc_nids = alc262_dmic_capsrc_nids,
12448 .dac_nids = alc262_dac_nids,
12449 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012450 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012451 .dig_out_nid = ALC262_DIGOUT_NID,
12452 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12453 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012454 .unsol_event = alc_sku_unsol_event,
12455 .setup = alc262_toshiba_s06_setup,
12456 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012457 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012458 [ALC262_TOSHIBA_RX1] = {
12459 .mixers = { alc262_toshiba_rx1_mixer },
12460 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12461 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12462 .dac_nids = alc262_dac_nids,
12463 .hp_nid = 0x03,
12464 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12465 .channel_mode = alc262_modes,
12466 .input_mux = &alc262_capture_source,
12467 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012468 .setup = alc262_hippo_setup,
12469 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012470 },
Tony Vroonba340e82009-02-02 19:01:30 +000012471 [ALC262_TYAN] = {
12472 .mixers = { alc262_tyan_mixer },
12473 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12474 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12475 .dac_nids = alc262_dac_nids,
12476 .hp_nid = 0x02,
12477 .dig_out_nid = ALC262_DIGOUT_NID,
12478 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12479 .channel_mode = alc262_modes,
12480 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012481 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012482 .setup = alc262_tyan_setup,
12483 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012484 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012485};
12486
12487static int patch_alc262(struct hda_codec *codec)
12488{
12489 struct alc_spec *spec;
12490 int board_config;
12491 int err;
12492
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012493 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012494 if (spec == NULL)
12495 return -ENOMEM;
12496
12497 codec->spec = spec;
12498#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012499 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12500 * under-run
12501 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012502 {
12503 int tmp;
12504 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12505 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12506 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12507 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12508 }
12509#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012510 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012511
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012512 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12513
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012514 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12515 alc262_models,
12516 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012517
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012518 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012519 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12520 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012521 board_config = ALC262_AUTO;
12522 }
12523
12524 if (board_config == ALC262_AUTO) {
12525 /* automatic parse from the BIOS config */
12526 err = alc262_parse_auto_config(codec);
12527 if (err < 0) {
12528 alc_free(codec);
12529 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012530 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012531 printk(KERN_INFO
12532 "hda_codec: Cannot set up configuration "
12533 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012534 board_config = ALC262_BASIC;
12535 }
12536 }
12537
Takashi Iwai07eba612009-02-19 08:06:35 +010012538 if (!spec->no_analog) {
12539 err = snd_hda_attach_beep_device(codec, 0x1);
12540 if (err < 0) {
12541 alc_free(codec);
12542 return err;
12543 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012544 }
12545
Kailang Yangdf694da2005-12-05 19:42:22 +010012546 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012547 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012548
Kailang Yangdf694da2005-12-05 19:42:22 +010012549 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12550 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012551
Kailang Yangdf694da2005-12-05 19:42:22 +010012552 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12553 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12554
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012555 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012556 int i;
12557 /* check whether the digital-mic has to be supported */
12558 for (i = 0; i < spec->input_mux->num_items; i++) {
12559 if (spec->input_mux->items[i].index >= 9)
12560 break;
12561 }
12562 if (i < spec->input_mux->num_items) {
12563 /* use only ADC0 */
12564 spec->adc_nids = alc262_dmic_adc_nids;
12565 spec->num_adc_nids = 1;
12566 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012567 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012568 /* all analog inputs */
12569 /* check whether NID 0x07 is valid */
12570 unsigned int wcap = get_wcaps(codec, 0x07);
12571
12572 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012573 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012574 if (wcap != AC_WID_AUD_IN) {
12575 spec->adc_nids = alc262_adc_nids_alt;
12576 spec->num_adc_nids =
12577 ARRAY_SIZE(alc262_adc_nids_alt);
12578 spec->capsrc_nids = alc262_capsrc_nids_alt;
12579 } else {
12580 spec->adc_nids = alc262_adc_nids;
12581 spec->num_adc_nids =
12582 ARRAY_SIZE(alc262_adc_nids);
12583 spec->capsrc_nids = alc262_capsrc_nids;
12584 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012585 }
12586 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012587 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012588 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010012589 if (!spec->no_analog && spec->cdefine.enable_pcbeep)
Takashi Iwai07eba612009-02-19 08:06:35 +010012590 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012591
Takashi Iwai2134ea42008-01-10 16:53:55 +010012592 spec->vmaster_nid = 0x0c;
12593
Kailang Yangdf694da2005-12-05 19:42:22 +010012594 codec->patch_ops = alc_patch_ops;
12595 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012596 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012597#ifdef CONFIG_SND_HDA_POWER_SAVE
12598 if (!spec->loopback.amplist)
12599 spec->loopback.amplist = alc262_loopbacks;
12600#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012601
Kailang Yangdf694da2005-12-05 19:42:22 +010012602 return 0;
12603}
12604
Kailang Yangdf694da2005-12-05 19:42:22 +010012605/*
Kailang Yanga361d842007-06-05 12:30:55 +020012606 * ALC268 channel source setting (2 channel)
12607 */
12608#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12609#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012610
Kailang Yanga361d842007-06-05 12:30:55 +020012611static hda_nid_t alc268_dac_nids[2] = {
12612 /* front, hp */
12613 0x02, 0x03
12614};
12615
12616static hda_nid_t alc268_adc_nids[2] = {
12617 /* ADC0-1 */
12618 0x08, 0x07
12619};
12620
12621static hda_nid_t alc268_adc_nids_alt[1] = {
12622 /* ADC0 */
12623 0x08
12624};
12625
Takashi Iwaie1406342008-02-11 18:32:32 +010012626static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12627
Kailang Yanga361d842007-06-05 12:30:55 +020012628static struct snd_kcontrol_new alc268_base_mixer[] = {
12629 /* output mixer control */
12630 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12631 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12632 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12633 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012634 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12635 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12636 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012637 { }
12638};
12639
Takashi Iwai42171c12009-05-08 14:11:43 +020012640static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12641 /* output mixer control */
12642 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12643 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12644 ALC262_HIPPO_MASTER_SWITCH,
12645 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12646 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12647 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12648 { }
12649};
12650
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012651/* bind Beep switches of both NID 0x0f and 0x10 */
12652static struct hda_bind_ctls alc268_bind_beep_sw = {
12653 .ops = &snd_hda_bind_sw,
12654 .values = {
12655 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12656 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12657 0
12658 },
12659};
12660
12661static struct snd_kcontrol_new alc268_beep_mixer[] = {
12662 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12663 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12664 { }
12665};
12666
Kailang Yangd1a991a2007-08-15 16:21:59 +020012667static struct hda_verb alc268_eapd_verbs[] = {
12668 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12669 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12670 { }
12671};
12672
Takashi Iwaid2738092007-08-16 14:59:45 +020012673/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012674static struct hda_verb alc268_toshiba_verbs[] = {
12675 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12676 { } /* end */
12677};
12678
12679/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012680/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012681static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12682 .ops = &snd_hda_bind_vol,
12683 .values = {
12684 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12685 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12686 0
12687 },
12688};
12689
Takashi Iwai889c4392007-08-23 18:56:52 +020012690/* mute/unmute internal speaker according to the hp jack and mute state */
12691static void alc268_acer_automute(struct hda_codec *codec, int force)
12692{
12693 struct alc_spec *spec = codec->spec;
12694 unsigned int mute;
12695
12696 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012697 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012698 spec->sense_updated = 1;
12699 }
12700 if (spec->jack_present)
12701 mute = HDA_AMP_MUTE; /* mute internal speaker */
12702 else /* unmute internal speaker if necessary */
12703 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12704 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12705 HDA_AMP_MUTE, mute);
12706}
12707
12708
12709/* bind hp and internal speaker mute (with plug check) */
12710static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12711 struct snd_ctl_elem_value *ucontrol)
12712{
12713 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12714 long *valp = ucontrol->value.integer.value;
12715 int change;
12716
Takashi Iwai8de56b72009-07-24 16:51:47 +020012717 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012718 if (change)
12719 alc268_acer_automute(codec, 0);
12720 return change;
12721}
Takashi Iwaid2738092007-08-16 14:59:45 +020012722
Kailang Yang8ef355d2008-08-26 13:10:22 +020012723static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12724 /* output mixer control */
12725 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12726 {
12727 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12728 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012729 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012730 .info = snd_hda_mixer_amp_switch_info,
12731 .get = snd_hda_mixer_amp_switch_get,
12732 .put = alc268_acer_master_sw_put,
12733 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12734 },
12735 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12736 { }
12737};
12738
Takashi Iwaid2738092007-08-16 14:59:45 +020012739static struct snd_kcontrol_new alc268_acer_mixer[] = {
12740 /* output mixer control */
12741 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12742 {
12743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12744 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012745 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020012746 .info = snd_hda_mixer_amp_switch_info,
12747 .get = snd_hda_mixer_amp_switch_get,
12748 .put = alc268_acer_master_sw_put,
12749 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12750 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012751 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12752 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12753 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012754 { }
12755};
12756
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012757static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12758 /* output mixer control */
12759 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12760 {
12761 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12762 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012763 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012764 .info = snd_hda_mixer_amp_switch_info,
12765 .get = snd_hda_mixer_amp_switch_get,
12766 .put = alc268_acer_master_sw_put,
12767 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12768 },
12769 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12770 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12771 { }
12772};
12773
Kailang Yang8ef355d2008-08-26 13:10:22 +020012774static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12775 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12776 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12777 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12778 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12779 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12780 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12781 { }
12782};
12783
Takashi Iwaid2738092007-08-16 14:59:45 +020012784static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012785 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12786 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012787 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12788 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012789 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12790 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012791 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12792 { }
12793};
12794
12795/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012796#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012797#define alc268_toshiba_setup alc262_hippo_setup
12798#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012799
12800static void alc268_acer_unsol_event(struct hda_codec *codec,
12801 unsigned int res)
12802{
Takashi Iwai889c4392007-08-23 18:56:52 +020012803 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012804 return;
12805 alc268_acer_automute(codec, 1);
12806}
12807
Takashi Iwai889c4392007-08-23 18:56:52 +020012808static void alc268_acer_init_hook(struct hda_codec *codec)
12809{
12810 alc268_acer_automute(codec, 1);
12811}
12812
Kailang Yang8ef355d2008-08-26 13:10:22 +020012813/* toggle speaker-output according to the hp-jack state */
12814static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12815{
12816 unsigned int present;
12817 unsigned char bits;
12818
Wu Fengguang864f92b2009-11-18 12:38:02 +080012819 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012820 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012821 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012822 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012823 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012824 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012825}
12826
Kailang Yang8ef355d2008-08-26 13:10:22 +020012827static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12828 unsigned int res)
12829{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012830 switch (res >> 26) {
12831 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012832 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012833 break;
12834 case ALC880_MIC_EVENT:
12835 alc_mic_automute(codec);
12836 break;
12837 }
12838}
12839
12840static void alc268_acer_lc_setup(struct hda_codec *codec)
12841{
12842 struct alc_spec *spec = codec->spec;
12843 spec->ext_mic.pin = 0x18;
12844 spec->ext_mic.mux_idx = 0;
12845 spec->int_mic.pin = 0x12;
12846 spec->int_mic.mux_idx = 6;
12847 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012848}
12849
12850static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12851{
12852 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012853 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012854}
12855
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012856static struct snd_kcontrol_new alc268_dell_mixer[] = {
12857 /* output mixer control */
12858 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12859 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12860 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12861 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12862 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12863 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12864 { }
12865};
12866
12867static struct hda_verb alc268_dell_verbs[] = {
12868 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12869 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12870 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012871 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012872 { }
12873};
12874
12875/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012876static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012877{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012878 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012879
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012880 spec->autocfg.hp_pins[0] = 0x15;
12881 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012882 spec->ext_mic.pin = 0x18;
12883 spec->ext_mic.mux_idx = 0;
12884 spec->int_mic.pin = 0x19;
12885 spec->int_mic.mux_idx = 1;
12886 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012887}
12888
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012889static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12890 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12891 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12892 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12893 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12894 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12895 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12896 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12897 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12898 { }
12899};
12900
12901static struct hda_verb alc267_quanta_il1_verbs[] = {
12902 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12903 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12904 { }
12905};
12906
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012907static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012908{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012909 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012910 spec->autocfg.hp_pins[0] = 0x15;
12911 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012912 spec->ext_mic.pin = 0x18;
12913 spec->ext_mic.mux_idx = 0;
12914 spec->int_mic.pin = 0x19;
12915 spec->int_mic.mux_idx = 1;
12916 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012917}
12918
Kailang Yanga361d842007-06-05 12:30:55 +020012919/*
12920 * generic initialization of ADC, input mixers and output mixers
12921 */
12922static struct hda_verb alc268_base_init_verbs[] = {
12923 /* Unmute DAC0-1 and set vol = 0 */
12924 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012925 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012926
12927 /*
12928 * Set up output mixers (0x0c - 0x0e)
12929 */
12930 /* set vol=0 to output mixers */
12931 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012932 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12933
12934 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12935 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12936
12937 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12938 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12939 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12940 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12941 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12942 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12943 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12944 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12945
12946 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12947 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12948 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12949 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012950 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012951
12952 /* set PCBEEP vol = 0, mute connections */
12953 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12954 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12955 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012956
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012957 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020012958
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012959 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
12960 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12961 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
12962 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012963
Kailang Yanga361d842007-06-05 12:30:55 +020012964 { }
12965};
12966
12967/*
12968 * generic initialization of ADC, input mixers and output mixers
12969 */
12970static struct hda_verb alc268_volume_init_verbs[] = {
12971 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010012972 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12973 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012974
12975 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12976 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12977 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12978 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12979 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12980
Kailang Yanga361d842007-06-05 12:30:55 +020012981 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012982 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12983 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12984
12985 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012986 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012987
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012988 /* set PCBEEP vol = 0, mute connections */
12989 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12990 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12991 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012992
12993 { }
12994};
12995
Takashi Iwaifdbc6622009-08-19 00:18:10 +020012996static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
12997 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12998 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12999 { } /* end */
13000};
13001
Kailang Yanga361d842007-06-05 12:30:55 +020013002static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13003 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13004 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013005 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013006 { } /* end */
13007};
13008
13009static struct snd_kcontrol_new alc268_capture_mixer[] = {
13010 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13011 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13012 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13013 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013014 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013015 { } /* end */
13016};
13017
13018static struct hda_input_mux alc268_capture_source = {
13019 .num_items = 4,
13020 .items = {
13021 { "Mic", 0x0 },
13022 { "Front Mic", 0x1 },
13023 { "Line", 0x2 },
13024 { "CD", 0x3 },
13025 },
13026};
13027
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013028static struct hda_input_mux alc268_acer_capture_source = {
13029 .num_items = 3,
13030 .items = {
13031 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013032 { "Internal Mic", 0x1 },
13033 { "Line", 0x2 },
13034 },
13035};
13036
13037static struct hda_input_mux alc268_acer_dmic_capture_source = {
13038 .num_items = 3,
13039 .items = {
13040 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013041 { "Internal Mic", 0x6 },
13042 { "Line", 0x2 },
13043 },
13044};
13045
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013046#ifdef CONFIG_SND_DEBUG
13047static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013048 /* Volume widgets */
13049 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13050 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13051 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13052 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13053 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13054 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13055 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13056 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13057 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13058 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13059 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13060 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13061 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013062 /* The below appears problematic on some hardwares */
13063 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013064 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13065 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13066 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13067 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13068
13069 /* Modes for retasking pin widgets */
13070 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13071 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13072 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13073 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13074
13075 /* Controls for GPIO pins, assuming they are configured as outputs */
13076 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13077 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13078 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13079 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13080
13081 /* Switches to allow the digital SPDIF output pin to be enabled.
13082 * The ALC268 does not have an SPDIF input.
13083 */
13084 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13085
13086 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13087 * this output to turn on an external amplifier.
13088 */
13089 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13090 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13091
13092 { } /* end */
13093};
13094#endif
13095
Kailang Yanga361d842007-06-05 12:30:55 +020013096/* create input playback/capture controls for the given pin */
13097static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13098 const char *ctlname, int idx)
13099{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013100 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013101 int err;
13102
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013103 switch (nid) {
13104 case 0x14:
13105 case 0x16:
13106 dac = 0x02;
13107 break;
13108 case 0x15:
Kailang Yang531d8792010-04-09 10:57:33 +020013109 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013110 dac = 0x03;
13111 break;
13112 default:
13113 return 0;
13114 }
13115 if (spec->multiout.dac_nids[0] != dac &&
13116 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013117 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013118 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013119 HDA_OUTPUT));
13120 if (err < 0)
13121 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013122 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13123 }
13124
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013125 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013126 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013127 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013128 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013129 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013130 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013131 if (err < 0)
13132 return err;
13133 return 0;
13134}
13135
13136/* add playback controls from the parsed DAC table */
13137static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13138 const struct auto_pin_cfg *cfg)
13139{
13140 hda_nid_t nid;
13141 int err;
13142
Kailang Yanga361d842007-06-05 12:30:55 +020013143 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013144
13145 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013146 if (nid) {
13147 const char *name;
13148 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13149 name = "Speaker";
13150 else
13151 name = "Front";
13152 err = alc268_new_analog_output(spec, nid, name, 0);
13153 if (err < 0)
13154 return err;
13155 }
Kailang Yanga361d842007-06-05 12:30:55 +020013156
13157 nid = cfg->speaker_pins[0];
13158 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013159 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013160 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13161 if (err < 0)
13162 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013163 } else {
13164 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13165 if (err < 0)
13166 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013167 }
13168 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013169 if (nid) {
13170 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13171 if (err < 0)
13172 return err;
13173 }
Kailang Yanga361d842007-06-05 12:30:55 +020013174
13175 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13176 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013177 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013178 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013179 if (err < 0)
13180 return err;
13181 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013182 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013183}
13184
13185/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013186static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013187 const struct auto_pin_cfg *cfg)
13188{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013189 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013190}
13191
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013192static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13193 hda_nid_t nid, int pin_type)
13194{
13195 int idx;
13196
13197 alc_set_pin_output(codec, nid, pin_type);
13198 if (nid == 0x14 || nid == 0x16)
13199 idx = 0;
13200 else
13201 idx = 1;
13202 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13203}
13204
13205static void alc268_auto_init_multi_out(struct hda_codec *codec)
13206{
13207 struct alc_spec *spec = codec->spec;
13208 hda_nid_t nid = spec->autocfg.line_out_pins[0];
13209 if (nid) {
13210 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13211 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13212 }
13213}
13214
13215static void alc268_auto_init_hp_out(struct hda_codec *codec)
13216{
13217 struct alc_spec *spec = codec->spec;
13218 hda_nid_t pin;
13219
13220 pin = spec->autocfg.hp_pins[0];
13221 if (pin)
13222 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
13223 pin = spec->autocfg.speaker_pins[0];
13224 if (pin)
13225 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
13226}
13227
Kailang Yanga361d842007-06-05 12:30:55 +020013228static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13229{
13230 struct alc_spec *spec = codec->spec;
13231 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13232 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13233 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13234 unsigned int dac_vol1, dac_vol2;
13235
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013236 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013237 snd_hda_codec_write(codec, speaker_nid, 0,
13238 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013239 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013240 snd_hda_codec_write(codec, 0x0f, 0,
13241 AC_VERB_SET_AMP_GAIN_MUTE,
13242 AMP_IN_UNMUTE(1));
13243 snd_hda_codec_write(codec, 0x10, 0,
13244 AC_VERB_SET_AMP_GAIN_MUTE,
13245 AMP_IN_UNMUTE(1));
13246 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013247 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013248 snd_hda_codec_write(codec, 0x0f, 0,
13249 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13250 snd_hda_codec_write(codec, 0x10, 0,
13251 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13252 }
13253
13254 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013255 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013256 dac_vol2 = AMP_OUT_ZERO;
13257 else if (line_nid == 0x15)
13258 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013259 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013260 dac_vol2 = AMP_OUT_ZERO;
13261 else if (hp_nid == 0x15)
13262 dac_vol1 = AMP_OUT_ZERO;
13263 if (line_nid != 0x16 || hp_nid != 0x16 ||
13264 spec->autocfg.line_out_pins[1] != 0x16 ||
13265 spec->autocfg.line_out_pins[2] != 0x16)
13266 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13267
13268 snd_hda_codec_write(codec, 0x02, 0,
13269 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13270 snd_hda_codec_write(codec, 0x03, 0,
13271 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13272}
13273
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013274/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013275#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13276#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013277#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013278#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13279
13280/*
13281 * BIOS auto configuration
13282 */
13283static int alc268_parse_auto_config(struct hda_codec *codec)
13284{
13285 struct alc_spec *spec = codec->spec;
13286 int err;
13287 static hda_nid_t alc268_ignore[] = { 0 };
13288
13289 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13290 alc268_ignore);
13291 if (err < 0)
13292 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013293 if (!spec->autocfg.line_outs) {
13294 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13295 spec->multiout.max_channels = 2;
13296 spec->no_analog = 1;
13297 goto dig_only;
13298 }
Kailang Yanga361d842007-06-05 12:30:55 +020013299 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013300 }
Kailang Yanga361d842007-06-05 12:30:55 +020013301 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13302 if (err < 0)
13303 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013304 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013305 if (err < 0)
13306 return err;
13307
13308 spec->multiout.max_channels = 2;
13309
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013310 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013311 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013312 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020013313 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013314 spec->dig_out_type = spec->autocfg.dig_out_type[0];
13315 }
Takashi Iwai603c4012008-07-30 15:01:44 +020013316 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013317 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013318
Takashi Iwai892981f2009-03-02 08:04:35 +010013319 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013320 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013321
Takashi Iwaid88897e2008-10-31 15:01:37 +010013322 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013323 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013324 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013325
Takashi Iwai776e1842007-08-29 15:07:11 +020013326 err = alc_auto_add_mic_boost(codec);
13327 if (err < 0)
13328 return err;
13329
Kailang Yang6227cdc2010-02-25 08:36:52 +010013330 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013331
Kailang Yanga361d842007-06-05 12:30:55 +020013332 return 1;
13333}
13334
Kailang Yanga361d842007-06-05 12:30:55 +020013335#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13336
13337/* init callback for auto-configuration model -- overriding the default init */
13338static void alc268_auto_init(struct hda_codec *codec)
13339{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013340 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013341 alc268_auto_init_multi_out(codec);
13342 alc268_auto_init_hp_out(codec);
13343 alc268_auto_init_mono_speaker_out(codec);
13344 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013345 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013346 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013347}
13348
13349/*
13350 * configuration and preset
13351 */
13352static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013353 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013354 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013355 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013356 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013357 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013358 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013359 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013360 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013361#ifdef CONFIG_SND_DEBUG
13362 [ALC268_TEST] = "test",
13363#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013364 [ALC268_AUTO] = "auto",
13365};
13366
13367static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013368 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013369 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013370 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013371 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013372 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013373 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13374 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013375 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013376 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13377 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013378 /* almost compatible with toshiba but with optional digital outs;
13379 * auto-probing seems working fine
13380 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013381 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013382 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013383 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013384 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013385 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013386 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013387 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013388 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020013389 {}
13390};
13391
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013392/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13393static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13394 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13395 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13396 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13397 ALC268_TOSHIBA),
13398 {}
13399};
13400
Kailang Yanga361d842007-06-05 12:30:55 +020013401static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013402 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013403 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13404 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013405 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13406 alc267_quanta_il1_verbs },
13407 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13408 .dac_nids = alc268_dac_nids,
13409 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13410 .adc_nids = alc268_adc_nids_alt,
13411 .hp_nid = 0x03,
13412 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13413 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013414 .unsol_event = alc_sku_unsol_event,
13415 .setup = alc267_quanta_il1_setup,
13416 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013417 },
Kailang Yanga361d842007-06-05 12:30:55 +020013418 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013419 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13420 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013421 .init_verbs = { alc268_base_init_verbs },
13422 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13423 .dac_nids = alc268_dac_nids,
13424 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13425 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013426 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013427 .hp_nid = 0x03,
13428 .dig_out_nid = ALC268_DIGOUT_NID,
13429 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13430 .channel_mode = alc268_modes,
13431 .input_mux = &alc268_capture_source,
13432 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013433 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013434 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013435 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013436 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13437 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013438 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13439 .dac_nids = alc268_dac_nids,
13440 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13441 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013442 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013443 .hp_nid = 0x03,
13444 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13445 .channel_mode = alc268_modes,
13446 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013447 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013448 .setup = alc268_toshiba_setup,
13449 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013450 },
13451 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013452 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013453 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013454 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13455 alc268_acer_verbs },
13456 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13457 .dac_nids = alc268_dac_nids,
13458 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13459 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013460 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013461 .hp_nid = 0x02,
13462 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13463 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013464 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013465 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013466 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013467 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013468 [ALC268_ACER_DMIC] = {
13469 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13470 alc268_beep_mixer },
13471 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13472 alc268_acer_verbs },
13473 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13474 .dac_nids = alc268_dac_nids,
13475 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13476 .adc_nids = alc268_adc_nids_alt,
13477 .capsrc_nids = alc268_capsrc_nids,
13478 .hp_nid = 0x02,
13479 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13480 .channel_mode = alc268_modes,
13481 .input_mux = &alc268_acer_dmic_capture_source,
13482 .unsol_event = alc268_acer_unsol_event,
13483 .init_hook = alc268_acer_init_hook,
13484 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013485 [ALC268_ACER_ASPIRE_ONE] = {
13486 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013487 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013488 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013489 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13490 alc268_acer_aspire_one_verbs },
13491 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13492 .dac_nids = alc268_dac_nids,
13493 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13494 .adc_nids = alc268_adc_nids_alt,
13495 .capsrc_nids = alc268_capsrc_nids,
13496 .hp_nid = 0x03,
13497 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13498 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013499 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013500 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013501 .init_hook = alc268_acer_lc_init_hook,
13502 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013503 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013504 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13505 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013506 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13507 alc268_dell_verbs },
13508 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13509 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013510 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13511 .adc_nids = alc268_adc_nids_alt,
13512 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013513 .hp_nid = 0x02,
13514 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13515 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013516 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013517 .setup = alc268_dell_setup,
13518 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013519 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013520 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013521 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13522 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013523 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13524 alc268_toshiba_verbs },
13525 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13526 .dac_nids = alc268_dac_nids,
13527 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13528 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013529 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013530 .hp_nid = 0x03,
13531 .dig_out_nid = ALC268_DIGOUT_NID,
13532 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13533 .channel_mode = alc268_modes,
13534 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013535 .setup = alc268_toshiba_setup,
13536 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013537 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013538#ifdef CONFIG_SND_DEBUG
13539 [ALC268_TEST] = {
13540 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13541 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13542 alc268_volume_init_verbs },
13543 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13544 .dac_nids = alc268_dac_nids,
13545 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13546 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013547 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013548 .hp_nid = 0x03,
13549 .dig_out_nid = ALC268_DIGOUT_NID,
13550 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13551 .channel_mode = alc268_modes,
13552 .input_mux = &alc268_capture_source,
13553 },
13554#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013555};
13556
13557static int patch_alc268(struct hda_codec *codec)
13558{
13559 struct alc_spec *spec;
13560 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013561 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013562
Julia Lawallef86f582009-12-19 08:18:03 +010013563 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013564 if (spec == NULL)
13565 return -ENOMEM;
13566
13567 codec->spec = spec;
13568
13569 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13570 alc268_models,
13571 alc268_cfg_tbl);
13572
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013573 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13574 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013575 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013576
Kailang Yanga361d842007-06-05 12:30:55 +020013577 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013578 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13579 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013580 board_config = ALC268_AUTO;
13581 }
13582
13583 if (board_config == ALC268_AUTO) {
13584 /* automatic parse from the BIOS config */
13585 err = alc268_parse_auto_config(codec);
13586 if (err < 0) {
13587 alc_free(codec);
13588 return err;
13589 } else if (!err) {
13590 printk(KERN_INFO
13591 "hda_codec: Cannot set up configuration "
13592 "from BIOS. Using base mode...\n");
13593 board_config = ALC268_3ST;
13594 }
13595 }
13596
13597 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013598 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013599
Kailang Yanga361d842007-06-05 12:30:55 +020013600 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13601 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013602 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013603
Kailang Yanga361d842007-06-05 12:30:55 +020013604 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13605
Takashi Iwai22971e32009-02-10 11:56:44 +010013606 has_beep = 0;
13607 for (i = 0; i < spec->num_mixers; i++) {
13608 if (spec->mixers[i] == alc268_beep_mixer) {
13609 has_beep = 1;
13610 break;
13611 }
13612 }
13613
13614 if (has_beep) {
13615 err = snd_hda_attach_beep_device(codec, 0x1);
13616 if (err < 0) {
13617 alc_free(codec);
13618 return err;
13619 }
13620 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13621 /* override the amp caps for beep generator */
13622 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013623 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13624 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13625 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13626 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013627 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013628
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013629 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013630 /* check whether NID 0x07 is valid */
13631 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013632 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013633
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013634 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013635 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013636 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013637 if (spec->auto_mic ||
13638 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013639 spec->adc_nids = alc268_adc_nids_alt;
13640 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013641 if (spec->auto_mic)
13642 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013643 if (spec->auto_mic || spec->input_mux->num_items == 1)
13644 add_mixer(spec, alc268_capture_nosrc_mixer);
13645 else
13646 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013647 } else {
13648 spec->adc_nids = alc268_adc_nids;
13649 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013650 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013651 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013652 /* set default input source */
13653 for (i = 0; i < spec->num_adc_nids; i++)
13654 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13655 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013656 i < spec->num_mux_defs ?
13657 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013658 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013659 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013660
13661 spec->vmaster_nid = 0x02;
13662
Kailang Yanga361d842007-06-05 12:30:55 +020013663 codec->patch_ops = alc_patch_ops;
13664 if (board_config == ALC268_AUTO)
13665 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013666
Kailang Yanga361d842007-06-05 12:30:55 +020013667 return 0;
13668}
13669
13670/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013671 * ALC269 channel source setting (2 channel)
13672 */
13673#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13674
13675#define alc269_dac_nids alc260_dac_nids
13676
13677static hda_nid_t alc269_adc_nids[1] = {
13678 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013679 0x08,
13680};
13681
Takashi Iwaie01bf502008-08-21 16:25:07 +020013682static hda_nid_t alc269_capsrc_nids[1] = {
13683 0x23,
13684};
13685
Kailang Yang84898e82010-02-04 14:16:14 +010013686static hda_nid_t alc269vb_adc_nids[1] = {
13687 /* ADC1 */
13688 0x09,
13689};
13690
13691static hda_nid_t alc269vb_capsrc_nids[1] = {
13692 0x22,
13693};
13694
Takashi Iwai66946352010-03-29 17:21:45 +020013695static hda_nid_t alc269_adc_candidates[] = {
13696 0x08, 0x09, 0x07,
13697};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013698
Kailang Yangf6a92242007-12-13 16:52:54 +010013699#define alc269_modes alc260_modes
13700#define alc269_capture_source alc880_lg_lw_capture_source
13701
13702static struct snd_kcontrol_new alc269_base_mixer[] = {
13703 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13704 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13705 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13706 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13707 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13708 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13709 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13710 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13711 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13712 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13713 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13714 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13715 { } /* end */
13716};
13717
Kailang Yang60db6b52008-08-26 13:13:00 +020013718static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13719 /* output mixer control */
13720 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13721 {
13722 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13723 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013724 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013725 .info = snd_hda_mixer_amp_switch_info,
13726 .get = snd_hda_mixer_amp_switch_get,
13727 .put = alc268_acer_master_sw_put,
13728 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13729 },
13730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13731 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13732 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13733 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13734 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13735 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013736 { }
13737};
13738
Tony Vroon64154832008-11-06 15:08:49 +000013739static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13740 /* output mixer control */
13741 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13742 {
13743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13744 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013745 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013746 .info = snd_hda_mixer_amp_switch_info,
13747 .get = snd_hda_mixer_amp_switch_get,
13748 .put = alc268_acer_master_sw_put,
13749 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13750 },
13751 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13752 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13753 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13754 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13755 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13756 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13757 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13758 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13759 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013760 { }
13761};
13762
Kailang Yang84898e82010-02-04 14:16:14 +010013763static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013764 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013765 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013766 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013767 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013768 { } /* end */
13769};
13770
Kailang Yang84898e82010-02-04 14:16:14 +010013771static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
13772 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13773 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13774 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13775 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13776 { } /* end */
13777};
13778
Kailang Yangf6a92242007-12-13 16:52:54 +010013779/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010013780static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
13781 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13782 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13783 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13784 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13785 { } /* end */
13786};
13787
13788static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013789 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13790 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013791 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13792 { } /* end */
13793};
13794
Kailang Yang84898e82010-02-04 14:16:14 +010013795static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
13796 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13797 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13798 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13799 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13800 { } /* end */
13801};
13802
13803static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
13804 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13805 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13806 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13807 { } /* end */
13808};
13809
Takashi Iwai26f5df22008-11-03 17:39:46 +010013810/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013811#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013812
Kailang Yang60db6b52008-08-26 13:13:00 +020013813static struct hda_verb alc269_quanta_fl1_verbs[] = {
13814 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13815 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13816 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13817 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13818 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13819 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13820 { }
13821};
13822
Tony Vroon64154832008-11-06 15:08:49 +000013823static struct hda_verb alc269_lifebook_verbs[] = {
13824 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13825 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13826 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13827 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13828 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13829 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13830 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13831 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13832 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13833 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13834 { }
13835};
13836
Kailang Yang60db6b52008-08-26 13:13:00 +020013837/* toggle speaker-output according to the hp-jack state */
13838static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13839{
13840 unsigned int present;
13841 unsigned char bits;
13842
Wu Fengguang864f92b2009-11-18 12:38:02 +080013843 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013844 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020013845 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013846 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013847 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013848 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013849
13850 snd_hda_codec_write(codec, 0x20, 0,
13851 AC_VERB_SET_COEF_INDEX, 0x0c);
13852 snd_hda_codec_write(codec, 0x20, 0,
13853 AC_VERB_SET_PROC_COEF, 0x680);
13854
13855 snd_hda_codec_write(codec, 0x20, 0,
13856 AC_VERB_SET_COEF_INDEX, 0x0c);
13857 snd_hda_codec_write(codec, 0x20, 0,
13858 AC_VERB_SET_PROC_COEF, 0x480);
13859}
13860
Tony Vroon64154832008-11-06 15:08:49 +000013861/* toggle speaker-output according to the hp-jacks state */
13862static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13863{
13864 unsigned int present;
13865 unsigned char bits;
13866
13867 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013868 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013869
13870 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013871 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013872
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013873 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000013874 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013875 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013876 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013877 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013878
13879 snd_hda_codec_write(codec, 0x20, 0,
13880 AC_VERB_SET_COEF_INDEX, 0x0c);
13881 snd_hda_codec_write(codec, 0x20, 0,
13882 AC_VERB_SET_PROC_COEF, 0x680);
13883
13884 snd_hda_codec_write(codec, 0x20, 0,
13885 AC_VERB_SET_COEF_INDEX, 0x0c);
13886 snd_hda_codec_write(codec, 0x20, 0,
13887 AC_VERB_SET_PROC_COEF, 0x480);
13888}
13889
Tony Vroon64154832008-11-06 15:08:49 +000013890static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13891{
13892 unsigned int present_laptop;
13893 unsigned int present_dock;
13894
Wu Fengguang864f92b2009-11-18 12:38:02 +080013895 present_laptop = snd_hda_jack_detect(codec, 0x18);
13896 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013897
13898 /* Laptop mic port overrides dock mic port, design decision */
13899 if (present_dock)
13900 snd_hda_codec_write(codec, 0x23, 0,
13901 AC_VERB_SET_CONNECT_SEL, 0x3);
13902 if (present_laptop)
13903 snd_hda_codec_write(codec, 0x23, 0,
13904 AC_VERB_SET_CONNECT_SEL, 0x0);
13905 if (!present_dock && !present_laptop)
13906 snd_hda_codec_write(codec, 0x23, 0,
13907 AC_VERB_SET_CONNECT_SEL, 0x1);
13908}
13909
Kailang Yang60db6b52008-08-26 13:13:00 +020013910static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13911 unsigned int res)
13912{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013913 switch (res >> 26) {
13914 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013915 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013916 break;
13917 case ALC880_MIC_EVENT:
13918 alc_mic_automute(codec);
13919 break;
13920 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013921}
13922
Tony Vroon64154832008-11-06 15:08:49 +000013923static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13924 unsigned int res)
13925{
13926 if ((res >> 26) == ALC880_HP_EVENT)
13927 alc269_lifebook_speaker_automute(codec);
13928 if ((res >> 26) == ALC880_MIC_EVENT)
13929 alc269_lifebook_mic_autoswitch(codec);
13930}
13931
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013932static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13933{
13934 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013935 spec->autocfg.hp_pins[0] = 0x15;
13936 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013937 spec->ext_mic.pin = 0x18;
13938 spec->ext_mic.mux_idx = 0;
13939 spec->int_mic.pin = 0x19;
13940 spec->int_mic.mux_idx = 1;
13941 spec->auto_mic = 1;
13942}
13943
Kailang Yang60db6b52008-08-26 13:13:00 +020013944static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13945{
13946 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013947 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013948}
13949
Tony Vroon64154832008-11-06 15:08:49 +000013950static void alc269_lifebook_init_hook(struct hda_codec *codec)
13951{
13952 alc269_lifebook_speaker_automute(codec);
13953 alc269_lifebook_mic_autoswitch(codec);
13954}
13955
Kailang Yang84898e82010-02-04 14:16:14 +010013956static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013957 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13958 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
13959 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13960 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13961 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13962 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13963 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13964 {}
13965};
13966
Kailang Yang84898e82010-02-04 14:16:14 +010013967static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013968 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13969 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
13970 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13971 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
13972 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13973 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13974 {}
13975};
13976
Kailang Yang84898e82010-02-04 14:16:14 +010013977static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
13978 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13979 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
13980 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13981 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13982 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13983 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13984 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13985 {}
13986};
13987
13988static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
13989 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13990 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
13991 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13992 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13993 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13994 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13995 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13996 {}
13997};
13998
Kailang Yang60db6b52008-08-26 13:13:00 +020013999/* toggle speaker-output according to the hp-jack state */
14000static void alc269_speaker_automute(struct hda_codec *codec)
14001{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014002 struct alc_spec *spec = codec->spec;
14003 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014004 unsigned int present;
14005 unsigned char bits;
14006
Kailang Yangebb83ee2009-12-17 12:23:00 +010014007 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014008 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014009 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014010 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014011 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014012 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014013}
14014
Kailang Yang60db6b52008-08-26 13:13:00 +020014015/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014016static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014017 unsigned int res)
14018{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014019 switch (res >> 26) {
14020 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014021 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014022 break;
14023 case ALC880_MIC_EVENT:
14024 alc_mic_automute(codec);
14025 break;
14026 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014027}
14028
Kailang Yang226b1ec2010-04-09 11:01:20 +020014029static void alc269_laptop_amic_setup(struct hda_codec *codec)
14030{
14031 struct alc_spec *spec = codec->spec;
14032 spec->autocfg.hp_pins[0] = 0x15;
14033 spec->autocfg.speaker_pins[0] = 0x14;
14034 spec->ext_mic.pin = 0x18;
14035 spec->ext_mic.mux_idx = 0;
14036 spec->int_mic.pin = 0x19;
14037 spec->int_mic.mux_idx = 1;
14038 spec->auto_mic = 1;
14039}
14040
Kailang Yang84898e82010-02-04 14:16:14 +010014041static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014042{
14043 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014044 spec->autocfg.hp_pins[0] = 0x15;
14045 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014046 spec->ext_mic.pin = 0x18;
14047 spec->ext_mic.mux_idx = 0;
14048 spec->int_mic.pin = 0x12;
14049 spec->int_mic.mux_idx = 5;
14050 spec->auto_mic = 1;
14051}
14052
Kailang Yang226b1ec2010-04-09 11:01:20 +020014053static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014054{
14055 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014056 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014057 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014058 spec->ext_mic.pin = 0x18;
14059 spec->ext_mic.mux_idx = 0;
14060 spec->int_mic.pin = 0x19;
14061 spec->int_mic.mux_idx = 1;
14062 spec->auto_mic = 1;
14063}
14064
Kailang Yang226b1ec2010-04-09 11:01:20 +020014065static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14066{
14067 struct alc_spec *spec = codec->spec;
14068 spec->autocfg.hp_pins[0] = 0x21;
14069 spec->autocfg.speaker_pins[0] = 0x14;
14070 spec->ext_mic.pin = 0x18;
14071 spec->ext_mic.mux_idx = 0;
14072 spec->int_mic.pin = 0x12;
14073 spec->int_mic.mux_idx = 6;
14074 spec->auto_mic = 1;
14075}
14076
Kailang Yang84898e82010-02-04 14:16:14 +010014077static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014078{
14079 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014080 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014081}
14082
Kailang Yangf6a92242007-12-13 16:52:54 +010014083/*
14084 * generic initialization of ADC, input mixers and output mixers
14085 */
14086static struct hda_verb alc269_init_verbs[] = {
14087 /*
14088 * Unmute ADC0 and set the default input to mic-in
14089 */
Kailang Yang84898e82010-02-04 14:16:14 +010014090 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014091
14092 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014093 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014094 */
14095 /* set vol=0 to output mixers */
14096 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14097 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14098
14099 /* set up input amps for analog loopback */
14100 /* Amp Indices: DAC = 0, mixer = 1 */
14101 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14102 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14103 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14104 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14105 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14106 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14107
14108 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14109 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14110 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14111 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14112 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14113 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14114 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14115
14116 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14117 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014118
Kailang Yang84898e82010-02-04 14:16:14 +010014119 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014120 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14121 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014122 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014123
14124 /* set EAPD */
14125 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014126 { }
14127};
14128
14129static struct hda_verb alc269vb_init_verbs[] = {
14130 /*
14131 * Unmute ADC0 and set the default input to mic-in
14132 */
14133 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14134
14135 /*
14136 * Set up output mixers (0x02 - 0x03)
14137 */
14138 /* set vol=0 to output mixers */
14139 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14140 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14141
14142 /* set up input amps for analog loopback */
14143 /* Amp Indices: DAC = 0, mixer = 1 */
14144 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14145 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14146 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14147 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14148 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14149 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14150
14151 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14152 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14153 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14154 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14155 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14156 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14157 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14158
14159 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14160 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14161
14162 /* FIXME: use Mux-type input source selection */
14163 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14164 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14165 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14166
14167 /* set EAPD */
14168 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014169 { }
14170};
14171
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014172#define alc269_auto_create_multi_out_ctls \
14173 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014174#define alc269_auto_create_input_ctls \
14175 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014176
14177#ifdef CONFIG_SND_HDA_POWER_SAVE
14178#define alc269_loopbacks alc880_loopbacks
14179#endif
14180
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014181/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014182#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14183#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14184#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14185#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14186
Takashi Iwaif03d3112009-03-05 14:18:16 +010014187static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14188 .substreams = 1,
14189 .channels_min = 2,
14190 .channels_max = 8,
14191 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14192 /* NID is set in alc_build_pcms */
14193 .ops = {
14194 .open = alc880_playback_pcm_open,
14195 .prepare = alc880_playback_pcm_prepare,
14196 .cleanup = alc880_playback_pcm_cleanup
14197 },
14198};
14199
14200static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14201 .substreams = 1,
14202 .channels_min = 2,
14203 .channels_max = 2,
14204 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14205 /* NID is set in alc_build_pcms */
14206};
14207
Takashi Iwaiad358792010-03-30 18:00:59 +020014208#ifdef CONFIG_SND_HDA_POWER_SAVE
14209static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14210{
14211 switch (codec->subsystem_id) {
14212 case 0x103c1586:
14213 return 1;
14214 }
14215 return 0;
14216}
14217
14218static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14219{
14220 /* update mute-LED according to the speaker mute state */
14221 if (nid == 0x01 || nid == 0x14) {
14222 int pinval;
14223 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14224 HDA_AMP_MUTE)
14225 pinval = 0x24;
14226 else
14227 pinval = 0x20;
14228 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014229 snd_hda_codec_update_cache(codec, 0x19, 0,
14230 AC_VERB_SET_PIN_WIDGET_CONTROL,
14231 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014232 }
14233 return alc_check_power_status(codec, nid);
14234}
14235#endif /* CONFIG_SND_HDA_POWER_SAVE */
14236
Takashi Iwai840b64c2010-07-13 22:49:01 +020014237static int alc275_setup_dual_adc(struct hda_codec *codec)
14238{
14239 struct alc_spec *spec = codec->spec;
14240
14241 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14242 return 0;
14243 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14244 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14245 if (spec->ext_mic.pin <= 0x12) {
14246 spec->private_adc_nids[0] = 0x08;
14247 spec->private_adc_nids[1] = 0x11;
14248 spec->private_capsrc_nids[0] = 0x23;
14249 spec->private_capsrc_nids[1] = 0x22;
14250 } else {
14251 spec->private_adc_nids[0] = 0x11;
14252 spec->private_adc_nids[1] = 0x08;
14253 spec->private_capsrc_nids[0] = 0x22;
14254 spec->private_capsrc_nids[1] = 0x23;
14255 }
14256 spec->adc_nids = spec->private_adc_nids;
14257 spec->capsrc_nids = spec->private_capsrc_nids;
14258 spec->num_adc_nids = 2;
14259 spec->dual_adc_switch = 1;
14260 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14261 spec->adc_nids[0], spec->adc_nids[1]);
14262 return 1;
14263 }
14264 return 0;
14265}
14266
Kailang Yangf6a92242007-12-13 16:52:54 +010014267/*
14268 * BIOS auto configuration
14269 */
14270static int alc269_parse_auto_config(struct hda_codec *codec)
14271{
14272 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014273 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014274 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14275
14276 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14277 alc269_ignore);
14278 if (err < 0)
14279 return err;
14280
14281 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14282 if (err < 0)
14283 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014284 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010014285 if (err < 0)
14286 return err;
14287
14288 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14289
Takashi Iwai0852d7a2009-02-11 11:35:15 +010014290 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010014291 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
14292
Takashi Iwai603c4012008-07-30 15:01:44 +020014293 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014294 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014295
Kailang Yang84898e82010-02-04 14:16:14 +010014296 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
14297 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014298 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014299 } else {
14300 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014301 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014302 }
14303
Kailang Yangf6a92242007-12-13 16:52:54 +010014304 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014305 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014306
14307 if (!alc275_setup_dual_adc(codec))
14308 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14309 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014310
Takashi Iwaie01bf502008-08-21 16:25:07 +020014311 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014312 if (!spec->dual_adc_switch)
14313 snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
Takashi Iwaie01bf502008-08-21 16:25:07 +020014314 0, AC_VERB_SET_CONNECT_SEL,
14315 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014316
14317 err = alc_auto_add_mic_boost(codec);
14318 if (err < 0)
14319 return err;
14320
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014321 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014322 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014323
Kailang Yangf6a92242007-12-13 16:52:54 +010014324 return 1;
14325}
14326
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014327#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14328#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014329#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14330
14331
14332/* init callback for auto-configuration model -- overriding the default init */
14333static void alc269_auto_init(struct hda_codec *codec)
14334{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014335 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014336 alc269_auto_init_multi_out(codec);
14337 alc269_auto_init_hp_out(codec);
14338 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014339 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014340 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014341}
14342
Takashi Iwaiff818c22010-04-12 08:59:25 +020014343enum {
14344 ALC269_FIXUP_SONY_VAIO,
14345};
14346
Tobias Klauserfbc25662010-05-20 10:40:55 +020014347static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
Takashi Iwaiff818c22010-04-12 08:59:25 +020014348 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14349 {}
14350};
14351
14352static const struct alc_fixup alc269_fixups[] = {
14353 [ALC269_FIXUP_SONY_VAIO] = {
14354 .verbs = alc269_sony_vaio_fixup_verbs
14355 },
14356};
14357
14358static struct snd_pci_quirk alc269_fixup_tbl[] = {
14359 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
14360 {}
14361};
14362
14363
Kailang Yangf6a92242007-12-13 16:52:54 +010014364/*
14365 * configuration and preset
14366 */
14367static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014368 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014369 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014370 [ALC269_AMIC] = "laptop-amic",
14371 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014372 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014373 [ALC269_LIFEBOOK] = "lifebook",
14374 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014375};
14376
14377static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014378 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020014379 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014380 ALC269_AMIC),
14381 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14382 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14383 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14384 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14385 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14386 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14387 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14388 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14389 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14390 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14391 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14392 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14393 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14394 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14395 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14396 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14397 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14398 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14399 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14400 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14401 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14402 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14403 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14404 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14405 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14406 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14407 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14408 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14409 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14410 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14411 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14412 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14413 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14414 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14415 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14416 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014417 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014418 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014419 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014420 ALC269_DMIC),
14421 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14422 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014423 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014424 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014425 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14426 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14427 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14428 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14429 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14430 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014431 {}
14432};
14433
14434static struct alc_config_preset alc269_presets[] = {
14435 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014436 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014437 .init_verbs = { alc269_init_verbs },
14438 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14439 .dac_nids = alc269_dac_nids,
14440 .hp_nid = 0x03,
14441 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14442 .channel_mode = alc269_modes,
14443 .input_mux = &alc269_capture_source,
14444 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014445 [ALC269_QUANTA_FL1] = {
14446 .mixers = { alc269_quanta_fl1_mixer },
14447 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14448 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14449 .dac_nids = alc269_dac_nids,
14450 .hp_nid = 0x03,
14451 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14452 .channel_mode = alc269_modes,
14453 .input_mux = &alc269_capture_source,
14454 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014455 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014456 .init_hook = alc269_quanta_fl1_init_hook,
14457 },
Kailang Yang84898e82010-02-04 14:16:14 +010014458 [ALC269_AMIC] = {
14459 .mixers = { alc269_laptop_mixer },
14460 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014461 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014462 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014463 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14464 .dac_nids = alc269_dac_nids,
14465 .hp_nid = 0x03,
14466 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14467 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014468 .unsol_event = alc269_laptop_unsol_event,
14469 .setup = alc269_laptop_amic_setup,
14470 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014471 },
Kailang Yang84898e82010-02-04 14:16:14 +010014472 [ALC269_DMIC] = {
14473 .mixers = { alc269_laptop_mixer },
14474 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014475 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014476 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014477 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14478 .dac_nids = alc269_dac_nids,
14479 .hp_nid = 0x03,
14480 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14481 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014482 .unsol_event = alc269_laptop_unsol_event,
14483 .setup = alc269_laptop_dmic_setup,
14484 .init_hook = alc269_laptop_inithook,
14485 },
14486 [ALC269VB_AMIC] = {
14487 .mixers = { alc269vb_laptop_mixer },
14488 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14489 .init_verbs = { alc269vb_init_verbs,
14490 alc269vb_laptop_amic_init_verbs },
14491 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14492 .dac_nids = alc269_dac_nids,
14493 .hp_nid = 0x03,
14494 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14495 .channel_mode = alc269_modes,
14496 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014497 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014498 .init_hook = alc269_laptop_inithook,
14499 },
14500 [ALC269VB_DMIC] = {
14501 .mixers = { alc269vb_laptop_mixer },
14502 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14503 .init_verbs = { alc269vb_init_verbs,
14504 alc269vb_laptop_dmic_init_verbs },
14505 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14506 .dac_nids = alc269_dac_nids,
14507 .hp_nid = 0x03,
14508 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14509 .channel_mode = alc269_modes,
14510 .unsol_event = alc269_laptop_unsol_event,
14511 .setup = alc269vb_laptop_dmic_setup,
14512 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014513 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014514 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014515 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014516 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014517 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014518 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014519 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14520 .dac_nids = alc269_dac_nids,
14521 .hp_nid = 0x03,
14522 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14523 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014524 .unsol_event = alc269_laptop_unsol_event,
14525 .setup = alc269_laptop_dmic_setup,
14526 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014527 },
Tony Vroon64154832008-11-06 15:08:49 +000014528 [ALC269_LIFEBOOK] = {
14529 .mixers = { alc269_lifebook_mixer },
14530 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14531 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14532 .dac_nids = alc269_dac_nids,
14533 .hp_nid = 0x03,
14534 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14535 .channel_mode = alc269_modes,
14536 .input_mux = &alc269_capture_source,
14537 .unsol_event = alc269_lifebook_unsol_event,
14538 .init_hook = alc269_lifebook_init_hook,
14539 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014540};
14541
14542static int patch_alc269(struct hda_codec *codec)
14543{
14544 struct alc_spec *spec;
14545 int board_config;
14546 int err;
Kailang Yang84898e82010-02-04 14:16:14 +010014547 int is_alc269vb = 0;
Kailang Yangf6a92242007-12-13 16:52:54 +010014548
14549 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14550 if (spec == NULL)
14551 return -ENOMEM;
14552
14553 codec->spec = spec;
14554
Kailang Yangda00c242010-03-19 11:23:45 +010014555 alc_auto_parse_customize_define(codec);
14556
Kailang Yang274693f2009-12-03 10:07:50 +010014557 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014558 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14559 spec->cdefine.platform_type == 1)
14560 alc_codec_rename(codec, "ALC271X");
14561 else
14562 alc_codec_rename(codec, "ALC259");
Kailang Yang84898e82010-02-04 14:16:14 +010014563 is_alc269vb = 1;
Kailang Yangc027ddc2010-03-19 11:33:06 +010014564 } else
14565 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010014566
Kailang Yangf6a92242007-12-13 16:52:54 +010014567 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14568 alc269_models,
14569 alc269_cfg_tbl);
14570
14571 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014572 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14573 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014574 board_config = ALC269_AUTO;
14575 }
14576
Takashi Iwaiff818c22010-04-12 08:59:25 +020014577 if (board_config == ALC269_AUTO)
14578 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
14579
Kailang Yangf6a92242007-12-13 16:52:54 +010014580 if (board_config == ALC269_AUTO) {
14581 /* automatic parse from the BIOS config */
14582 err = alc269_parse_auto_config(codec);
14583 if (err < 0) {
14584 alc_free(codec);
14585 return err;
14586 } else if (!err) {
14587 printk(KERN_INFO
14588 "hda_codec: Cannot set up configuration "
14589 "from BIOS. Using base mode...\n");
14590 board_config = ALC269_BASIC;
14591 }
14592 }
14593
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014594 err = snd_hda_attach_beep_device(codec, 0x1);
14595 if (err < 0) {
14596 alc_free(codec);
14597 return err;
14598 }
14599
Kailang Yangf6a92242007-12-13 16:52:54 +010014600 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014601 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014602
Kailang Yang84898e82010-02-04 14:16:14 +010014603 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014604 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14605 * fix the sample rate of analog I/O to 44.1kHz
14606 */
14607 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14608 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020014609 } else if (spec->dual_adc_switch) {
14610 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14611 /* switch ADC dynamically */
14612 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014613 } else {
14614 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14615 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14616 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014617 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14618 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14619
Takashi Iwai66946352010-03-29 17:21:45 +020014620 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
14621 if (!is_alc269vb) {
14622 spec->adc_nids = alc269_adc_nids;
14623 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14624 spec->capsrc_nids = alc269_capsrc_nids;
14625 } else {
14626 spec->adc_nids = alc269vb_adc_nids;
14627 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14628 spec->capsrc_nids = alc269vb_capsrc_nids;
14629 }
Kailang Yang84898e82010-02-04 14:16:14 +010014630 }
14631
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014632 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014633 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010014634 if (spec->cdefine.enable_pcbeep)
14635 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014636
Takashi Iwaiff818c22010-04-12 08:59:25 +020014637 if (board_config == ALC269_AUTO)
14638 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
14639
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014640 spec->vmaster_nid = 0x02;
14641
Kailang Yangf6a92242007-12-13 16:52:54 +010014642 codec->patch_ops = alc_patch_ops;
14643 if (board_config == ALC269_AUTO)
14644 spec->init_hook = alc269_auto_init;
14645#ifdef CONFIG_SND_HDA_POWER_SAVE
14646 if (!spec->loopback.amplist)
14647 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014648 if (alc269_mic2_for_mute_led(codec))
14649 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014650#endif
14651
14652 return 0;
14653}
14654
14655/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014656 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14657 */
14658
14659/*
14660 * set the path ways for 2 channel output
14661 * need to set the codec line out and mic 1 pin widgets to inputs
14662 */
14663static struct hda_verb alc861_threestack_ch2_init[] = {
14664 /* set pin widget 1Ah (line in) for input */
14665 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014666 /* set pin widget 18h (mic1/2) for input, for mic also enable
14667 * the vref
14668 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014669 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14670
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014671 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14672#if 0
14673 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14674 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14675#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014676 { } /* end */
14677};
14678/*
14679 * 6ch mode
14680 * need to set the codec line out and mic 1 pin widgets to outputs
14681 */
14682static struct hda_verb alc861_threestack_ch6_init[] = {
14683 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14684 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14685 /* set pin widget 18h (mic1) for output (CLFE)*/
14686 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14687
14688 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014689 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014690
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014691 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14692#if 0
14693 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14694 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14695#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014696 { } /* end */
14697};
14698
14699static struct hda_channel_mode alc861_threestack_modes[2] = {
14700 { 2, alc861_threestack_ch2_init },
14701 { 6, alc861_threestack_ch6_init },
14702};
Takashi Iwai22309c32006-08-09 16:57:28 +020014703/* Set mic1 as input and unmute the mixer */
14704static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
14705 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14706 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14707 { } /* end */
14708};
14709/* Set mic1 as output and mute mixer */
14710static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
14711 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14712 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14713 { } /* end */
14714};
14715
14716static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
14717 { 2, alc861_uniwill_m31_ch2_init },
14718 { 4, alc861_uniwill_m31_ch4_init },
14719};
Kailang Yangdf694da2005-12-05 19:42:22 +010014720
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014721/* Set mic1 and line-in as input and unmute the mixer */
14722static struct hda_verb alc861_asus_ch2_init[] = {
14723 /* set pin widget 1Ah (line in) for input */
14724 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014725 /* set pin widget 18h (mic1/2) for input, for mic also enable
14726 * the vref
14727 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014728 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14729
14730 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14731#if 0
14732 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14733 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14734#endif
14735 { } /* end */
14736};
14737/* Set mic1 nad line-in as output and mute mixer */
14738static struct hda_verb alc861_asus_ch6_init[] = {
14739 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14740 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14741 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14742 /* set pin widget 18h (mic1) for output (CLFE)*/
14743 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14744 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14745 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14746 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14747
14748 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14749#if 0
14750 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14751 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14752#endif
14753 { } /* end */
14754};
14755
14756static struct hda_channel_mode alc861_asus_modes[2] = {
14757 { 2, alc861_asus_ch2_init },
14758 { 6, alc861_asus_ch6_init },
14759};
14760
Kailang Yangdf694da2005-12-05 19:42:22 +010014761/* patch-ALC861 */
14762
14763static struct snd_kcontrol_new alc861_base_mixer[] = {
14764 /* output mixer control */
14765 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14766 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14767 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14768 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14769 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14770
14771 /*Input mixer control */
14772 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14773 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14774 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14775 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14776 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14777 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14778 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14779 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14780 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14781 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014782
Kailang Yangdf694da2005-12-05 19:42:22 +010014783 { } /* end */
14784};
14785
14786static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14787 /* output mixer control */
14788 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14789 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14790 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14791 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14792 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14793
14794 /* Input mixer control */
14795 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14796 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14797 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14798 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14799 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14800 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14801 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14802 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14803 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14804 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014805
Kailang Yangdf694da2005-12-05 19:42:22 +010014806 {
14807 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14808 .name = "Channel Mode",
14809 .info = alc_ch_mode_info,
14810 .get = alc_ch_mode_get,
14811 .put = alc_ch_mode_put,
14812 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14813 },
14814 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014815};
14816
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014817static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014818 /* output mixer control */
14819 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14820 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14821 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014822
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014823 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014824};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014825
Takashi Iwai22309c32006-08-09 16:57:28 +020014826static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14827 /* output mixer control */
14828 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14829 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14830 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14831 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14832 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14833
14834 /* Input mixer control */
14835 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14836 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14837 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14838 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14839 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14840 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14841 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14842 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14843 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14844 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014845
Takashi Iwai22309c32006-08-09 16:57:28 +020014846 {
14847 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14848 .name = "Channel Mode",
14849 .info = alc_ch_mode_info,
14850 .get = alc_ch_mode_get,
14851 .put = alc_ch_mode_put,
14852 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14853 },
14854 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014855};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014856
14857static struct snd_kcontrol_new alc861_asus_mixer[] = {
14858 /* output mixer control */
14859 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14860 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14861 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14862 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14863 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14864
14865 /* Input mixer control */
14866 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14867 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14868 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14869 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14870 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14871 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14872 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14873 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14874 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014875 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14876
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014877 {
14878 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14879 .name = "Channel Mode",
14880 .info = alc_ch_mode_info,
14881 .get = alc_ch_mode_get,
14882 .put = alc_ch_mode_put,
14883 .private_value = ARRAY_SIZE(alc861_asus_modes),
14884 },
14885 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014886};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014887
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014888/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014889static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014890 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14891 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014892 { }
14893};
14894
Kailang Yangdf694da2005-12-05 19:42:22 +010014895/*
14896 * generic initialization of ADC, input mixers and output mixers
14897 */
14898static struct hda_verb alc861_base_init_verbs[] = {
14899 /*
14900 * Unmute ADC0 and set the default input to mic-in
14901 */
14902 /* port-A for surround (rear panel) */
14903 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14904 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14905 /* port-B for mic-in (rear panel) with vref */
14906 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14907 /* port-C for line-in (rear panel) */
14908 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14909 /* port-D for Front */
14910 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14911 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14912 /* port-E for HP out (front panel) */
14913 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14914 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014915 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014916 /* port-F for mic-in (front panel) with vref */
14917 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14918 /* port-G for CLFE (rear panel) */
14919 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14920 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14921 /* port-H for side (rear panel) */
14922 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14923 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14924 /* CD-in */
14925 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14926 /* route front mic to ADC1*/
14927 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14928 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014929
Kailang Yangdf694da2005-12-05 19:42:22 +010014930 /* Unmute DAC0~3 & spdif out*/
14931 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14932 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14933 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14934 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14935 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014936
Kailang Yangdf694da2005-12-05 19:42:22 +010014937 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14938 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14939 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14940 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14941 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014942
Kailang Yangdf694da2005-12-05 19:42:22 +010014943 /* Unmute Stereo Mixer 15 */
14944 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14945 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14946 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014947 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014948
14949 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14950 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14951 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14952 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14953 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14954 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14955 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14956 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014957 /* hp used DAC 3 (Front) */
14958 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014959 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14960
14961 { }
14962};
14963
14964static struct hda_verb alc861_threestack_init_verbs[] = {
14965 /*
14966 * Unmute ADC0 and set the default input to mic-in
14967 */
14968 /* port-A for surround (rear panel) */
14969 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14970 /* port-B for mic-in (rear panel) with vref */
14971 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14972 /* port-C for line-in (rear panel) */
14973 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14974 /* port-D for Front */
14975 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14976 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14977 /* port-E for HP out (front panel) */
14978 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14979 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014980 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014981 /* port-F for mic-in (front panel) with vref */
14982 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14983 /* port-G for CLFE (rear panel) */
14984 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14985 /* port-H for side (rear panel) */
14986 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14987 /* CD-in */
14988 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14989 /* route front mic to ADC1*/
14990 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14991 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14992 /* Unmute DAC0~3 & spdif out*/
14993 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14994 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14995 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14996 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14997 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014998
Kailang Yangdf694da2005-12-05 19:42:22 +010014999 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15000 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15001 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15002 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15003 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015004
Kailang Yangdf694da2005-12-05 19:42:22 +010015005 /* Unmute Stereo Mixer 15 */
15006 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15007 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15008 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015009 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015010
15011 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15012 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15013 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15014 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15015 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15016 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15017 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15018 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015019 /* hp used DAC 3 (Front) */
15020 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015021 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15022 { }
15023};
Takashi Iwai22309c32006-08-09 16:57:28 +020015024
15025static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15026 /*
15027 * Unmute ADC0 and set the default input to mic-in
15028 */
15029 /* port-A for surround (rear panel) */
15030 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15031 /* port-B for mic-in (rear panel) with vref */
15032 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15033 /* port-C for line-in (rear panel) */
15034 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15035 /* port-D for Front */
15036 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15037 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15038 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015039 /* this has to be set to VREF80 */
15040 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015041 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015042 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015043 /* port-F for mic-in (front panel) with vref */
15044 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15045 /* port-G for CLFE (rear panel) */
15046 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15047 /* port-H for side (rear panel) */
15048 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15049 /* CD-in */
15050 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15051 /* route front mic to ADC1*/
15052 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15053 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15054 /* Unmute DAC0~3 & spdif out*/
15055 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15056 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15057 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15058 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015060
Takashi Iwai22309c32006-08-09 16:57:28 +020015061 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15062 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15063 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15064 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15065 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015066
Takashi Iwai22309c32006-08-09 16:57:28 +020015067 /* Unmute Stereo Mixer 15 */
15068 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15069 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15070 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015071 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015072
15073 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15074 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15075 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15076 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15077 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15078 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15079 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15080 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015081 /* hp used DAC 3 (Front) */
15082 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015083 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15084 { }
15085};
15086
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015087static struct hda_verb alc861_asus_init_verbs[] = {
15088 /*
15089 * Unmute ADC0 and set the default input to mic-in
15090 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015091 /* port-A for surround (rear panel)
15092 * according to codec#0 this is the HP jack
15093 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015094 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15095 /* route front PCM to HP */
15096 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15097 /* port-B for mic-in (rear panel) with vref */
15098 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15099 /* port-C for line-in (rear panel) */
15100 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15101 /* port-D for Front */
15102 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15103 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15104 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015105 /* this has to be set to VREF80 */
15106 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015107 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015108 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015109 /* port-F for mic-in (front panel) with vref */
15110 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15111 /* port-G for CLFE (rear panel) */
15112 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15113 /* port-H for side (rear panel) */
15114 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15115 /* CD-in */
15116 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15117 /* route front mic to ADC1*/
15118 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15119 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15120 /* Unmute DAC0~3 & spdif out*/
15121 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15122 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15123 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15124 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15125 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15126 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15127 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15128 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15129 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15130 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015131
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015132 /* Unmute Stereo Mixer 15 */
15133 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15134 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15135 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015136 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015137
15138 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15139 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15140 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15141 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15142 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15143 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15144 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15145 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015146 /* hp used DAC 3 (Front) */
15147 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015148 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15149 { }
15150};
15151
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015152/* additional init verbs for ASUS laptops */
15153static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15154 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15155 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15156 { }
15157};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015158
Kailang Yangdf694da2005-12-05 19:42:22 +010015159/*
15160 * generic initialization of ADC, input mixers and output mixers
15161 */
15162static struct hda_verb alc861_auto_init_verbs[] = {
15163 /*
15164 * Unmute ADC0 and set the default input to mic-in
15165 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015166 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015167 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015168
Kailang Yangdf694da2005-12-05 19:42:22 +010015169 /* Unmute DAC0~3 & spdif out*/
15170 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15171 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15172 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15173 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15174 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015175
Kailang Yangdf694da2005-12-05 19:42:22 +010015176 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15177 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15178 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15179 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15180 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015181
Kailang Yangdf694da2005-12-05 19:42:22 +010015182 /* Unmute Stereo Mixer 15 */
15183 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15185 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15186 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15187
Takashi Iwai1c209302009-07-22 15:17:45 +020015188 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15189 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15190 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15191 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15192 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15193 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15194 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15195 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015196
15197 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15198 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015199 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15200 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015201 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15202 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015203 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15204 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015205
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015206 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015207
15208 { }
15209};
15210
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015211static struct hda_verb alc861_toshiba_init_verbs[] = {
15212 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015213
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015214 { }
15215};
15216
15217/* toggle speaker-output according to the hp-jack state */
15218static void alc861_toshiba_automute(struct hda_codec *codec)
15219{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015220 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015221
Takashi Iwai47fd8302007-08-10 17:11:07 +020015222 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15223 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15224 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15225 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015226}
15227
15228static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15229 unsigned int res)
15230{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015231 if ((res >> 26) == ALC880_HP_EVENT)
15232 alc861_toshiba_automute(codec);
15233}
15234
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015235/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015236#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15237#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15238#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15239#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15240
15241
15242#define ALC861_DIGOUT_NID 0x07
15243
15244static struct hda_channel_mode alc861_8ch_modes[1] = {
15245 { 8, NULL }
15246};
15247
15248static hda_nid_t alc861_dac_nids[4] = {
15249 /* front, surround, clfe, side */
15250 0x03, 0x06, 0x05, 0x04
15251};
15252
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015253static hda_nid_t alc660_dac_nids[3] = {
15254 /* front, clfe, surround */
15255 0x03, 0x05, 0x06
15256};
15257
Kailang Yangdf694da2005-12-05 19:42:22 +010015258static hda_nid_t alc861_adc_nids[1] = {
15259 /* ADC0-2 */
15260 0x08,
15261};
15262
15263static struct hda_input_mux alc861_capture_source = {
15264 .num_items = 5,
15265 .items = {
15266 { "Mic", 0x0 },
15267 { "Front Mic", 0x3 },
15268 { "Line", 0x1 },
15269 { "CD", 0x4 },
15270 { "Mixer", 0x5 },
15271 },
15272};
15273
Takashi Iwai1c209302009-07-22 15:17:45 +020015274static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15275{
15276 struct alc_spec *spec = codec->spec;
15277 hda_nid_t mix, srcs[5];
15278 int i, j, num;
15279
15280 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15281 return 0;
15282 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15283 if (num < 0)
15284 return 0;
15285 for (i = 0; i < num; i++) {
15286 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015287 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015288 if (type != AC_WID_AUD_OUT)
15289 continue;
15290 for (j = 0; j < spec->multiout.num_dacs; j++)
15291 if (spec->multiout.dac_nids[j] == srcs[i])
15292 break;
15293 if (j >= spec->multiout.num_dacs)
15294 return srcs[i];
15295 }
15296 return 0;
15297}
15298
Kailang Yangdf694da2005-12-05 19:42:22 +010015299/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015300static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015301 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015302{
Takashi Iwai1c209302009-07-22 15:17:45 +020015303 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015304 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015305 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015306
15307 spec->multiout.dac_nids = spec->private_dac_nids;
15308 for (i = 0; i < cfg->line_outs; i++) {
15309 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015310 dac = alc861_look_for_dac(codec, nid);
15311 if (!dac)
15312 continue;
15313 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015314 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015315 return 0;
15316}
15317
Takashi Iwai1c209302009-07-22 15:17:45 +020015318static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15319 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015320{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015321 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015322 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15323}
15324
15325/* add playback controls from the parsed DAC table */
15326static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15327 const struct auto_pin_cfg *cfg)
15328{
15329 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015330 static const char *chname[4] = {
15331 "Front", "Surround", NULL /*CLFE*/, "Side"
15332 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015333 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015334 int i, err;
15335
15336 if (cfg->line_outs == 1) {
15337 const char *pfx = NULL;
15338 if (!cfg->hp_outs)
15339 pfx = "Master";
15340 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15341 pfx = "Speaker";
15342 if (pfx) {
15343 nid = spec->multiout.dac_nids[0];
15344 return alc861_create_out_sw(codec, pfx, nid, 3);
15345 }
15346 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015347
15348 for (i = 0; i < cfg->line_outs; i++) {
15349 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015350 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015351 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015352 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015353 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015354 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015355 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015356 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015357 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015358 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015359 return err;
15360 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015361 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015362 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015363 return err;
15364 }
15365 }
15366 return 0;
15367}
15368
Takashi Iwai1c209302009-07-22 15:17:45 +020015369static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015370{
Takashi Iwai1c209302009-07-22 15:17:45 +020015371 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015372 int err;
15373 hda_nid_t nid;
15374
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015375 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015376 return 0;
15377
15378 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015379 nid = alc861_look_for_dac(codec, pin);
15380 if (nid) {
15381 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15382 if (err < 0)
15383 return err;
15384 spec->multiout.hp_nid = nid;
15385 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015386 }
15387 return 0;
15388}
15389
15390/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015391static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015392 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015393{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015394 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015395}
15396
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015397static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15398 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015399 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015400{
Takashi Iwai1c209302009-07-22 15:17:45 +020015401 hda_nid_t mix, srcs[5];
15402 int i, num;
15403
Jacek Luczak564c5be2008-05-03 18:41:23 +020015404 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15405 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015406 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015407 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015408 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15409 return;
15410 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15411 if (num < 0)
15412 return;
15413 for (i = 0; i < num; i++) {
15414 unsigned int mute;
15415 if (srcs[i] == dac || srcs[i] == 0x15)
15416 mute = AMP_IN_UNMUTE(i);
15417 else
15418 mute = AMP_IN_MUTE(i);
15419 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15420 mute);
15421 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015422}
15423
15424static void alc861_auto_init_multi_out(struct hda_codec *codec)
15425{
15426 struct alc_spec *spec = codec->spec;
15427 int i;
15428
15429 for (i = 0; i < spec->autocfg.line_outs; i++) {
15430 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015431 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015432 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015433 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015434 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015435 }
15436}
15437
15438static void alc861_auto_init_hp_out(struct hda_codec *codec)
15439{
15440 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015441
Takashi Iwai15870f02009-10-05 08:25:13 +020015442 if (spec->autocfg.hp_outs)
15443 alc861_auto_set_output_and_unmute(codec,
15444 spec->autocfg.hp_pins[0],
15445 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015446 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015447 if (spec->autocfg.speaker_outs)
15448 alc861_auto_set_output_and_unmute(codec,
15449 spec->autocfg.speaker_pins[0],
15450 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015451 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015452}
15453
15454static void alc861_auto_init_analog_input(struct hda_codec *codec)
15455{
15456 struct alc_spec *spec = codec->spec;
15457 int i;
15458
15459 for (i = 0; i < AUTO_PIN_LAST; i++) {
15460 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010015461 if (nid >= 0x0c && nid <= 0x11)
15462 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010015463 }
15464}
15465
15466/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015467/* return 1 if successful, 0 if the proper config is not found,
15468 * or a negative error code
15469 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015470static int alc861_parse_auto_config(struct hda_codec *codec)
15471{
15472 struct alc_spec *spec = codec->spec;
15473 int err;
15474 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15475
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015476 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15477 alc861_ignore);
15478 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015479 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015480 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015481 return 0; /* can't find valid BIOS pin config */
15482
Takashi Iwai1c209302009-07-22 15:17:45 +020015483 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015484 if (err < 0)
15485 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015486 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015487 if (err < 0)
15488 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015489 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015490 if (err < 0)
15491 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015492 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015493 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015494 return err;
15495
15496 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15497
Takashi Iwai0852d7a2009-02-11 11:35:15 +010015498 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015499 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
15500
Takashi Iwai603c4012008-07-30 15:01:44 +020015501 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015502 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015503
Takashi Iwaid88897e2008-10-31 15:01:37 +010015504 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015505
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015506 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015507 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015508
15509 spec->adc_nids = alc861_adc_nids;
15510 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015511 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015512
Kailang Yang6227cdc2010-02-25 08:36:52 +010015513 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015514
Kailang Yangdf694da2005-12-05 19:42:22 +010015515 return 1;
15516}
15517
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015518/* additional initialization for auto-configuration model */
15519static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015520{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015521 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015522 alc861_auto_init_multi_out(codec);
15523 alc861_auto_init_hp_out(codec);
15524 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015525 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015526 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015527}
15528
Takashi Iwaicb53c622007-08-10 17:21:45 +020015529#ifdef CONFIG_SND_HDA_POWER_SAVE
15530static struct hda_amp_list alc861_loopbacks[] = {
15531 { 0x15, HDA_INPUT, 0 },
15532 { 0x15, HDA_INPUT, 1 },
15533 { 0x15, HDA_INPUT, 2 },
15534 { 0x15, HDA_INPUT, 3 },
15535 { } /* end */
15536};
15537#endif
15538
Kailang Yangdf694da2005-12-05 19:42:22 +010015539
15540/*
15541 * configuration and preset
15542 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015543static const char *alc861_models[ALC861_MODEL_LAST] = {
15544 [ALC861_3ST] = "3stack",
15545 [ALC660_3ST] = "3stack-660",
15546 [ALC861_3ST_DIG] = "3stack-dig",
15547 [ALC861_6ST_DIG] = "6stack-dig",
15548 [ALC861_UNIWILL_M31] = "uniwill-m31",
15549 [ALC861_TOSHIBA] = "toshiba",
15550 [ALC861_ASUS] = "asus",
15551 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15552 [ALC861_AUTO] = "auto",
15553};
15554
15555static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015556 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015557 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15558 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15559 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015560 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015561 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015562 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015563 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15564 * Any other models that need this preset?
15565 */
15566 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015567 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15568 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015569 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15570 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15571 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15572 /* FIXME: the below seems conflict */
15573 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15574 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15575 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015576 {}
15577};
15578
15579static struct alc_config_preset alc861_presets[] = {
15580 [ALC861_3ST] = {
15581 .mixers = { alc861_3ST_mixer },
15582 .init_verbs = { alc861_threestack_init_verbs },
15583 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15584 .dac_nids = alc861_dac_nids,
15585 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15586 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015587 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015588 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15589 .adc_nids = alc861_adc_nids,
15590 .input_mux = &alc861_capture_source,
15591 },
15592 [ALC861_3ST_DIG] = {
15593 .mixers = { alc861_base_mixer },
15594 .init_verbs = { alc861_threestack_init_verbs },
15595 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15596 .dac_nids = alc861_dac_nids,
15597 .dig_out_nid = ALC861_DIGOUT_NID,
15598 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15599 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015600 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015601 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15602 .adc_nids = alc861_adc_nids,
15603 .input_mux = &alc861_capture_source,
15604 },
15605 [ALC861_6ST_DIG] = {
15606 .mixers = { alc861_base_mixer },
15607 .init_verbs = { alc861_base_init_verbs },
15608 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15609 .dac_nids = alc861_dac_nids,
15610 .dig_out_nid = ALC861_DIGOUT_NID,
15611 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15612 .channel_mode = alc861_8ch_modes,
15613 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15614 .adc_nids = alc861_adc_nids,
15615 .input_mux = &alc861_capture_source,
15616 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015617 [ALC660_3ST] = {
15618 .mixers = { alc861_3ST_mixer },
15619 .init_verbs = { alc861_threestack_init_verbs },
15620 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15621 .dac_nids = alc660_dac_nids,
15622 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15623 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015624 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015625 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15626 .adc_nids = alc861_adc_nids,
15627 .input_mux = &alc861_capture_source,
15628 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015629 [ALC861_UNIWILL_M31] = {
15630 .mixers = { alc861_uniwill_m31_mixer },
15631 .init_verbs = { alc861_uniwill_m31_init_verbs },
15632 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15633 .dac_nids = alc861_dac_nids,
15634 .dig_out_nid = ALC861_DIGOUT_NID,
15635 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15636 .channel_mode = alc861_uniwill_m31_modes,
15637 .need_dac_fix = 1,
15638 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15639 .adc_nids = alc861_adc_nids,
15640 .input_mux = &alc861_capture_source,
15641 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015642 [ALC861_TOSHIBA] = {
15643 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015644 .init_verbs = { alc861_base_init_verbs,
15645 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015646 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15647 .dac_nids = alc861_dac_nids,
15648 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15649 .channel_mode = alc883_3ST_2ch_modes,
15650 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15651 .adc_nids = alc861_adc_nids,
15652 .input_mux = &alc861_capture_source,
15653 .unsol_event = alc861_toshiba_unsol_event,
15654 .init_hook = alc861_toshiba_automute,
15655 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015656 [ALC861_ASUS] = {
15657 .mixers = { alc861_asus_mixer },
15658 .init_verbs = { alc861_asus_init_verbs },
15659 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15660 .dac_nids = alc861_dac_nids,
15661 .dig_out_nid = ALC861_DIGOUT_NID,
15662 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15663 .channel_mode = alc861_asus_modes,
15664 .need_dac_fix = 1,
15665 .hp_nid = 0x06,
15666 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15667 .adc_nids = alc861_adc_nids,
15668 .input_mux = &alc861_capture_source,
15669 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015670 [ALC861_ASUS_LAPTOP] = {
15671 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15672 .init_verbs = { alc861_asus_init_verbs,
15673 alc861_asus_laptop_init_verbs },
15674 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15675 .dac_nids = alc861_dac_nids,
15676 .dig_out_nid = ALC861_DIGOUT_NID,
15677 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15678 .channel_mode = alc883_3ST_2ch_modes,
15679 .need_dac_fix = 1,
15680 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15681 .adc_nids = alc861_adc_nids,
15682 .input_mux = &alc861_capture_source,
15683 },
15684};
Kailang Yangdf694da2005-12-05 19:42:22 +010015685
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015686/* Pin config fixes */
15687enum {
15688 PINFIX_FSC_AMILO_PI1505,
15689};
15690
15691static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
15692 { 0x0b, 0x0221101f }, /* HP */
15693 { 0x0f, 0x90170310 }, /* speaker */
15694 { }
15695};
15696
15697static const struct alc_fixup alc861_fixups[] = {
15698 [PINFIX_FSC_AMILO_PI1505] = {
15699 .pins = alc861_fsc_amilo_pi1505_pinfix
15700 },
15701};
15702
15703static struct snd_pci_quirk alc861_fixup_tbl[] = {
15704 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15705 {}
15706};
Kailang Yangdf694da2005-12-05 19:42:22 +010015707
15708static int patch_alc861(struct hda_codec *codec)
15709{
15710 struct alc_spec *spec;
15711 int board_config;
15712 int err;
15713
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015714 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015715 if (spec == NULL)
15716 return -ENOMEM;
15717
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015718 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015719
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015720 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15721 alc861_models,
15722 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015723
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015724 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015725 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15726 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015727 board_config = ALC861_AUTO;
15728 }
15729
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015730 if (board_config == ALC861_AUTO)
15731 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015732
Kailang Yangdf694da2005-12-05 19:42:22 +010015733 if (board_config == ALC861_AUTO) {
15734 /* automatic parse from the BIOS config */
15735 err = alc861_parse_auto_config(codec);
15736 if (err < 0) {
15737 alc_free(codec);
15738 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015739 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015740 printk(KERN_INFO
15741 "hda_codec: Cannot set up configuration "
15742 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015743 board_config = ALC861_3ST_DIG;
15744 }
15745 }
15746
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015747 err = snd_hda_attach_beep_device(codec, 0x23);
15748 if (err < 0) {
15749 alc_free(codec);
15750 return err;
15751 }
15752
Kailang Yangdf694da2005-12-05 19:42:22 +010015753 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015754 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015755
Kailang Yangdf694da2005-12-05 19:42:22 +010015756 spec->stream_analog_playback = &alc861_pcm_analog_playback;
15757 spec->stream_analog_capture = &alc861_pcm_analog_capture;
15758
Kailang Yangdf694da2005-12-05 19:42:22 +010015759 spec->stream_digital_playback = &alc861_pcm_digital_playback;
15760 spec->stream_digital_capture = &alc861_pcm_digital_capture;
15761
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015762 if (!spec->cap_mixer)
15763 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015764 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15765
Takashi Iwai2134ea42008-01-10 16:53:55 +010015766 spec->vmaster_nid = 0x03;
15767
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015768 if (board_config == ALC861_AUTO)
15769 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
15770
Kailang Yangdf694da2005-12-05 19:42:22 +010015771 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015772 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015773 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015774#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015775 spec->power_hook = alc_power_eapd;
15776#endif
15777 }
15778#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015779 if (!spec->loopback.amplist)
15780 spec->loopback.amplist = alc861_loopbacks;
15781#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015782
Kailang Yangdf694da2005-12-05 19:42:22 +010015783 return 0;
15784}
15785
15786/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015787 * ALC861-VD support
15788 *
15789 * Based on ALC882
15790 *
15791 * In addition, an independent DAC
15792 */
15793#define ALC861VD_DIGOUT_NID 0x06
15794
15795static hda_nid_t alc861vd_dac_nids[4] = {
15796 /* front, surr, clfe, side surr */
15797 0x02, 0x03, 0x04, 0x05
15798};
15799
15800/* dac_nids for ALC660vd are in a different order - according to
15801 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015802 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015803 * of ALC660vd codecs, but for now there is only 3stack mixer
15804 * - and it is the same as in 861vd.
15805 * adc_nids in ALC660vd are (is) the same as in 861vd
15806 */
15807static hda_nid_t alc660vd_dac_nids[3] = {
15808 /* front, rear, clfe, rear_surr */
15809 0x02, 0x04, 0x03
15810};
15811
15812static hda_nid_t alc861vd_adc_nids[1] = {
15813 /* ADC0 */
15814 0x09,
15815};
15816
Takashi Iwaie1406342008-02-11 18:32:32 +010015817static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15818
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015819/* input MUX */
15820/* FIXME: should be a matrix-type input source selection */
15821static struct hda_input_mux alc861vd_capture_source = {
15822 .num_items = 4,
15823 .items = {
15824 { "Mic", 0x0 },
15825 { "Front Mic", 0x1 },
15826 { "Line", 0x2 },
15827 { "CD", 0x4 },
15828 },
15829};
15830
Kailang Yang272a5272007-05-14 11:00:38 +020015831static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015832 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015833 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015834 { "Ext Mic", 0x0 },
15835 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015836 },
15837};
15838
Kailang Yangd1a991a2007-08-15 16:21:59 +020015839static struct hda_input_mux alc861vd_hp_capture_source = {
15840 .num_items = 2,
15841 .items = {
15842 { "Front Mic", 0x0 },
15843 { "ATAPI Mic", 0x1 },
15844 },
15845};
15846
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015847/*
15848 * 2ch mode
15849 */
15850static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15851 { 2, NULL }
15852};
15853
15854/*
15855 * 6ch mode
15856 */
15857static struct hda_verb alc861vd_6stack_ch6_init[] = {
15858 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15859 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15860 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15861 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15862 { } /* end */
15863};
15864
15865/*
15866 * 8ch mode
15867 */
15868static struct hda_verb alc861vd_6stack_ch8_init[] = {
15869 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15870 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15871 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15872 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15873 { } /* end */
15874};
15875
15876static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15877 { 6, alc861vd_6stack_ch6_init },
15878 { 8, alc861vd_6stack_ch8_init },
15879};
15880
15881static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15882 {
15883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15884 .name = "Channel Mode",
15885 .info = alc_ch_mode_info,
15886 .get = alc_ch_mode_get,
15887 .put = alc_ch_mode_put,
15888 },
15889 { } /* end */
15890};
15891
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015892/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15893 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15894 */
15895static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15896 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15897 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15898
15899 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15900 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15901
15902 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15903 HDA_OUTPUT),
15904 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15905 HDA_OUTPUT),
15906 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15907 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15908
15909 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15910 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15911
15912 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15913
15914 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15915 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15916 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15917
15918 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15919 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15920 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15921
15922 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15923 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15924
15925 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15926 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15927
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015928 { } /* end */
15929};
15930
15931static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15932 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15933 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15934
15935 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15936
15937 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15938 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15939 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15940
15941 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15942 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15943 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15944
15945 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15946 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15947
15948 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15949 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15950
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015951 { } /* end */
15952};
15953
Kailang Yangbdd148a2007-05-08 15:19:08 +020015954static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
15955 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15956 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
15957 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15958
15959 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15960
15961 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15962 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15963 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15964
15965 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15966 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15967 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15968
15969 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15970 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15971
15972 { } /* end */
15973};
15974
Tobin Davisb419f342008-03-07 11:57:51 +010015975/* Pin assignment: Speaker=0x14, HP = 0x15,
15976 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020015977 */
15978static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010015979 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15980 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015981 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15982 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010015983 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
15984 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15985 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15986 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
15987 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15988 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015989 { } /* end */
15990};
15991
Kailang Yangd1a991a2007-08-15 16:21:59 +020015992/* Pin assignment: Speaker=0x14, Line-out = 0x15,
15993 * Front Mic=0x18, ATAPI Mic = 0x19,
15994 */
15995static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
15996 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15997 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15998 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15999 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16000 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16001 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16002 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16003 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016004
Kailang Yangd1a991a2007-08-15 16:21:59 +020016005 { } /* end */
16006};
16007
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016008/*
16009 * generic initialization of ADC, input mixers and output mixers
16010 */
16011static struct hda_verb alc861vd_volume_init_verbs[] = {
16012 /*
16013 * Unmute ADC0 and set the default input to mic-in
16014 */
16015 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16016 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16017
16018 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16019 * the analog-loopback mixer widget
16020 */
16021 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016022 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16025 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16026 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016027
16028 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016029 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16030 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16031 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016033
16034 /*
16035 * Set up output mixers (0x02 - 0x05)
16036 */
16037 /* set vol=0 to output mixers */
16038 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16039 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16040 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16041 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16042
16043 /* set up input amps for analog loopback */
16044 /* Amp Indices: DAC = 0, mixer = 1 */
16045 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16046 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16047 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16048 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16049 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16050 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16051 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16052 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16053
16054 { }
16055};
16056
16057/*
16058 * 3-stack pin configuration:
16059 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16060 */
16061static struct hda_verb alc861vd_3stack_init_verbs[] = {
16062 /*
16063 * Set pin mode and muting
16064 */
16065 /* set front pin widgets 0x14 for output */
16066 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16067 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16068 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16069
16070 /* Mic (rear) pin: input vref at 80% */
16071 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16072 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16073 /* Front Mic pin: input vref at 80% */
16074 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16075 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16076 /* Line In pin: input */
16077 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16078 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16079 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16080 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16081 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16082 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16083 /* CD pin widget for input */
16084 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16085
16086 { }
16087};
16088
16089/*
16090 * 6-stack pin configuration:
16091 */
16092static struct hda_verb alc861vd_6stack_init_verbs[] = {
16093 /*
16094 * Set pin mode and muting
16095 */
16096 /* set front pin widgets 0x14 for output */
16097 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16098 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16099 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16100
16101 /* Rear Pin: output 1 (0x0d) */
16102 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16103 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16104 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16105 /* CLFE Pin: output 2 (0x0e) */
16106 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16107 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16108 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16109 /* Side Pin: output 3 (0x0f) */
16110 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16111 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16112 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16113
16114 /* Mic (rear) pin: input vref at 80% */
16115 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16116 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16117 /* Front Mic pin: input vref at 80% */
16118 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16119 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16120 /* Line In pin: input */
16121 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16122 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16123 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16124 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16125 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16126 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16127 /* CD pin widget for input */
16128 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16129
16130 { }
16131};
16132
Kailang Yangbdd148a2007-05-08 15:19:08 +020016133static struct hda_verb alc861vd_eapd_verbs[] = {
16134 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16135 { }
16136};
16137
Kailang Yangf9423e72008-05-27 12:32:25 +020016138static struct hda_verb alc660vd_eapd_verbs[] = {
16139 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16140 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16141 { }
16142};
16143
Kailang Yangbdd148a2007-05-08 15:19:08 +020016144static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16145 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16146 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16147 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16148 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016149 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016150 {}
16151};
16152
Kailang Yangbdd148a2007-05-08 15:19:08 +020016153static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16154{
16155 unsigned int present;
16156 unsigned char bits;
16157
Wu Fengguang864f92b2009-11-18 12:38:02 +080016158 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016159 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016160
Takashi Iwai47fd8302007-08-10 17:11:07 +020016161 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16162 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016163}
16164
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016165static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016166{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016167 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016168 spec->autocfg.hp_pins[0] = 0x1b;
16169 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016170}
16171
16172static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16173{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016174 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016175 alc861vd_lenovo_mic_automute(codec);
16176}
16177
16178static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16179 unsigned int res)
16180{
16181 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016182 case ALC880_MIC_EVENT:
16183 alc861vd_lenovo_mic_automute(codec);
16184 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016185 default:
16186 alc_automute_amp_unsol_event(codec, res);
16187 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016188 }
16189}
16190
Kailang Yang272a5272007-05-14 11:00:38 +020016191static struct hda_verb alc861vd_dallas_verbs[] = {
16192 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16193 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16194 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16195 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16196
16197 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16198 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16199 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16200 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16201 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16202 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16203 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16204 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016205
Kailang Yang272a5272007-05-14 11:00:38 +020016206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16207 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16208 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16209 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16210 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16211 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16212 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16213 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16214
16215 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16216 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16217 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16218 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16219 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16220 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16221 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16222 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16223
16224 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16225 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16226 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16227 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16228
16229 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016230 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016231 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16232
16233 { } /* end */
16234};
16235
16236/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016237static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016238{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016239 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016240
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016241 spec->autocfg.hp_pins[0] = 0x15;
16242 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016243}
16244
Takashi Iwaicb53c622007-08-10 17:21:45 +020016245#ifdef CONFIG_SND_HDA_POWER_SAVE
16246#define alc861vd_loopbacks alc880_loopbacks
16247#endif
16248
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016249/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016250#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16251#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16252#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16253#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16254
16255/*
16256 * configuration and preset
16257 */
16258static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16259 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016260 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016261 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016262 [ALC861VD_3ST] = "3stack",
16263 [ALC861VD_3ST_DIG] = "3stack-digout",
16264 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016265 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016266 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016267 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016268 [ALC861VD_AUTO] = "auto",
16269};
16270
16271static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016272 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16273 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016274 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016275 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016276 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016277 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016278 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016279 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016280 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016281 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016282 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016283 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016284 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016285 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016286 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016287 {}
16288};
16289
16290static struct alc_config_preset alc861vd_presets[] = {
16291 [ALC660VD_3ST] = {
16292 .mixers = { alc861vd_3st_mixer },
16293 .init_verbs = { alc861vd_volume_init_verbs,
16294 alc861vd_3stack_init_verbs },
16295 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16296 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016297 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16298 .channel_mode = alc861vd_3stack_2ch_modes,
16299 .input_mux = &alc861vd_capture_source,
16300 },
Mike Crash6963f842007-06-25 12:12:51 +020016301 [ALC660VD_3ST_DIG] = {
16302 .mixers = { alc861vd_3st_mixer },
16303 .init_verbs = { alc861vd_volume_init_verbs,
16304 alc861vd_3stack_init_verbs },
16305 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16306 .dac_nids = alc660vd_dac_nids,
16307 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016308 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16309 .channel_mode = alc861vd_3stack_2ch_modes,
16310 .input_mux = &alc861vd_capture_source,
16311 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016312 [ALC861VD_3ST] = {
16313 .mixers = { alc861vd_3st_mixer },
16314 .init_verbs = { alc861vd_volume_init_verbs,
16315 alc861vd_3stack_init_verbs },
16316 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16317 .dac_nids = alc861vd_dac_nids,
16318 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16319 .channel_mode = alc861vd_3stack_2ch_modes,
16320 .input_mux = &alc861vd_capture_source,
16321 },
16322 [ALC861VD_3ST_DIG] = {
16323 .mixers = { alc861vd_3st_mixer },
16324 .init_verbs = { alc861vd_volume_init_verbs,
16325 alc861vd_3stack_init_verbs },
16326 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16327 .dac_nids = alc861vd_dac_nids,
16328 .dig_out_nid = ALC861VD_DIGOUT_NID,
16329 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16330 .channel_mode = alc861vd_3stack_2ch_modes,
16331 .input_mux = &alc861vd_capture_source,
16332 },
16333 [ALC861VD_6ST_DIG] = {
16334 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16335 .init_verbs = { alc861vd_volume_init_verbs,
16336 alc861vd_6stack_init_verbs },
16337 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16338 .dac_nids = alc861vd_dac_nids,
16339 .dig_out_nid = ALC861VD_DIGOUT_NID,
16340 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16341 .channel_mode = alc861vd_6stack_modes,
16342 .input_mux = &alc861vd_capture_source,
16343 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016344 [ALC861VD_LENOVO] = {
16345 .mixers = { alc861vd_lenovo_mixer },
16346 .init_verbs = { alc861vd_volume_init_verbs,
16347 alc861vd_3stack_init_verbs,
16348 alc861vd_eapd_verbs,
16349 alc861vd_lenovo_unsol_verbs },
16350 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16351 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016352 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16353 .channel_mode = alc861vd_3stack_2ch_modes,
16354 .input_mux = &alc861vd_capture_source,
16355 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016356 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016357 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016358 },
Kailang Yang272a5272007-05-14 11:00:38 +020016359 [ALC861VD_DALLAS] = {
16360 .mixers = { alc861vd_dallas_mixer },
16361 .init_verbs = { alc861vd_dallas_verbs },
16362 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16363 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016364 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16365 .channel_mode = alc861vd_3stack_2ch_modes,
16366 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016367 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016368 .setup = alc861vd_dallas_setup,
16369 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016370 },
16371 [ALC861VD_HP] = {
16372 .mixers = { alc861vd_hp_mixer },
16373 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16374 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16375 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016376 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016377 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16378 .channel_mode = alc861vd_3stack_2ch_modes,
16379 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016380 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016381 .setup = alc861vd_dallas_setup,
16382 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016383 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016384 [ALC660VD_ASUS_V1S] = {
16385 .mixers = { alc861vd_lenovo_mixer },
16386 .init_verbs = { alc861vd_volume_init_verbs,
16387 alc861vd_3stack_init_verbs,
16388 alc861vd_eapd_verbs,
16389 alc861vd_lenovo_unsol_verbs },
16390 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16391 .dac_nids = alc660vd_dac_nids,
16392 .dig_out_nid = ALC861VD_DIGOUT_NID,
16393 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16394 .channel_mode = alc861vd_3stack_2ch_modes,
16395 .input_mux = &alc861vd_capture_source,
16396 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016397 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016398 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016399 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016400};
16401
16402/*
16403 * BIOS auto configuration
16404 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016405static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16406 const struct auto_pin_cfg *cfg)
16407{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016408 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016409}
16410
16411
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016412static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16413 hda_nid_t nid, int pin_type, int dac_idx)
16414{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016415 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016416}
16417
16418static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16419{
16420 struct alc_spec *spec = codec->spec;
16421 int i;
16422
16423 for (i = 0; i <= HDA_SIDE; i++) {
16424 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016425 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016426 if (nid)
16427 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016428 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016429 }
16430}
16431
16432
16433static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16434{
16435 struct alc_spec *spec = codec->spec;
16436 hda_nid_t pin;
16437
16438 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016439 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016440 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016441 pin = spec->autocfg.speaker_pins[0];
16442 if (pin)
16443 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016444}
16445
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016446#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16447
16448static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16449{
16450 struct alc_spec *spec = codec->spec;
16451 int i;
16452
16453 for (i = 0; i < AUTO_PIN_LAST; i++) {
16454 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020016455 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016456 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016457 if (nid != ALC861VD_PIN_CD_NID &&
16458 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016459 snd_hda_codec_write(codec, nid, 0,
16460 AC_VERB_SET_AMP_GAIN_MUTE,
16461 AMP_OUT_MUTE);
16462 }
16463 }
16464}
16465
Takashi Iwaif511b012008-08-15 16:46:42 +020016466#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16467
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016468#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16469#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16470
16471/* add playback controls from the parsed DAC table */
16472/* Based on ALC880 version. But ALC861VD has separate,
16473 * different NIDs for mute/unmute switch and volume control */
16474static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16475 const struct auto_pin_cfg *cfg)
16476{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016477 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16478 hda_nid_t nid_v, nid_s;
16479 int i, err;
16480
16481 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016482 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016483 continue;
16484 nid_v = alc861vd_idx_to_mixer_vol(
16485 alc880_dac_to_idx(
16486 spec->multiout.dac_nids[i]));
16487 nid_s = alc861vd_idx_to_mixer_switch(
16488 alc880_dac_to_idx(
16489 spec->multiout.dac_nids[i]));
16490
16491 if (i == 2) {
16492 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016493 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16494 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016495 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16496 HDA_OUTPUT));
16497 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016498 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016499 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16500 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016501 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16502 HDA_OUTPUT));
16503 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016504 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016505 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16506 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016507 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16508 HDA_INPUT));
16509 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016510 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016511 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16512 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016513 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16514 HDA_INPUT));
16515 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016516 return err;
16517 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016518 const char *pfx;
16519 if (cfg->line_outs == 1 &&
16520 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16521 if (!cfg->hp_pins)
16522 pfx = "Speaker";
16523 else
16524 pfx = "PCM";
16525 } else
16526 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016527 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016528 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16529 HDA_OUTPUT));
16530 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016531 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016532 if (cfg->line_outs == 1 &&
16533 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16534 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016535 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016536 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016537 HDA_INPUT));
16538 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016539 return err;
16540 }
16541 }
16542 return 0;
16543}
16544
16545/* add playback controls for speaker and HP outputs */
16546/* Based on ALC880 version. But ALC861VD has separate,
16547 * different NIDs for mute/unmute switch and volume control */
16548static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16549 hda_nid_t pin, const char *pfx)
16550{
16551 hda_nid_t nid_v, nid_s;
16552 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016553
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016554 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016555 return 0;
16556
16557 if (alc880_is_fixed_pin(pin)) {
16558 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16559 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016560 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016561 spec->multiout.hp_nid = nid_v;
16562 else
16563 spec->multiout.extra_out_nid[0] = nid_v;
16564 /* control HP volume/switch on the output mixer amp */
16565 nid_v = alc861vd_idx_to_mixer_vol(
16566 alc880_fixed_pin_idx(pin));
16567 nid_s = alc861vd_idx_to_mixer_switch(
16568 alc880_fixed_pin_idx(pin));
16569
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016570 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016571 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16572 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016573 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016574 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016575 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16576 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016577 return err;
16578 } else if (alc880_is_multi_pin(pin)) {
16579 /* set manual connection */
16580 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016581 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016582 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16583 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016584 return err;
16585 }
16586 return 0;
16587}
16588
16589/* parse the BIOS configuration and set up the alc_spec
16590 * return 1 if successful, 0 if the proper config is not found,
16591 * or a negative error code
16592 * Based on ALC880 version - had to change it to override
16593 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16594static int alc861vd_parse_auto_config(struct hda_codec *codec)
16595{
16596 struct alc_spec *spec = codec->spec;
16597 int err;
16598 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
16599
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016600 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16601 alc861vd_ignore);
16602 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016603 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016604 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016605 return 0; /* can't find valid BIOS pin config */
16606
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016607 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16608 if (err < 0)
16609 return err;
16610 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16611 if (err < 0)
16612 return err;
16613 err = alc861vd_auto_create_extra_out(spec,
16614 spec->autocfg.speaker_pins[0],
16615 "Speaker");
16616 if (err < 0)
16617 return err;
16618 err = alc861vd_auto_create_extra_out(spec,
16619 spec->autocfg.hp_pins[0],
16620 "Headphone");
16621 if (err < 0)
16622 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016623 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016624 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016625 return err;
16626
16627 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16628
Takashi Iwai0852d7a2009-02-11 11:35:15 +010016629 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016630 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
16631
Takashi Iwai603c4012008-07-30 15:01:44 +020016632 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016633 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016634
Takashi Iwaid88897e2008-10-31 15:01:37 +010016635 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016636
16637 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016638 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016639
Takashi Iwai776e1842007-08-29 15:07:11 +020016640 err = alc_auto_add_mic_boost(codec);
16641 if (err < 0)
16642 return err;
16643
Kailang Yang6227cdc2010-02-25 08:36:52 +010016644 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016645
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016646 return 1;
16647}
16648
16649/* additional initialization for auto-configuration model */
16650static void alc861vd_auto_init(struct hda_codec *codec)
16651{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016652 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016653 alc861vd_auto_init_multi_out(codec);
16654 alc861vd_auto_init_hp_out(codec);
16655 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016656 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016657 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016658 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016659}
16660
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016661enum {
16662 ALC660VD_FIX_ASUS_GPIO1
16663};
16664
16665/* reset GPIO1 */
16666static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
16667 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16668 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16669 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16670 { }
16671};
16672
16673static const struct alc_fixup alc861vd_fixups[] = {
16674 [ALC660VD_FIX_ASUS_GPIO1] = {
16675 .verbs = alc660vd_fix_asus_gpio1_verbs,
16676 },
16677};
16678
16679static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
16680 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16681 {}
16682};
16683
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016684static int patch_alc861vd(struct hda_codec *codec)
16685{
16686 struct alc_spec *spec;
16687 int err, board_config;
16688
16689 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16690 if (spec == NULL)
16691 return -ENOMEM;
16692
16693 codec->spec = spec;
16694
16695 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16696 alc861vd_models,
16697 alc861vd_cfg_tbl);
16698
16699 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016700 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16701 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016702 board_config = ALC861VD_AUTO;
16703 }
16704
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016705 if (board_config == ALC861VD_AUTO)
16706 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016707
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016708 if (board_config == ALC861VD_AUTO) {
16709 /* automatic parse from the BIOS config */
16710 err = alc861vd_parse_auto_config(codec);
16711 if (err < 0) {
16712 alc_free(codec);
16713 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016714 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016715 printk(KERN_INFO
16716 "hda_codec: Cannot set up configuration "
16717 "from BIOS. Using base mode...\n");
16718 board_config = ALC861VD_3ST;
16719 }
16720 }
16721
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016722 err = snd_hda_attach_beep_device(codec, 0x23);
16723 if (err < 0) {
16724 alc_free(codec);
16725 return err;
16726 }
16727
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016728 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016729 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016730
Kailang Yang2f893282008-05-27 12:14:47 +020016731 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016732 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016733 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016734 }
16735
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016736 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16737 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16738
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016739 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16740 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16741
Takashi Iwaidd704692009-08-11 08:45:11 +020016742 if (!spec->adc_nids) {
16743 spec->adc_nids = alc861vd_adc_nids;
16744 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16745 }
16746 if (!spec->capsrc_nids)
16747 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016748
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016749 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016750 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016751
Takashi Iwai2134ea42008-01-10 16:53:55 +010016752 spec->vmaster_nid = 0x02;
16753
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016754 if (board_config == ALC861VD_AUTO)
16755 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
16756
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016757 codec->patch_ops = alc_patch_ops;
16758
16759 if (board_config == ALC861VD_AUTO)
16760 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016761#ifdef CONFIG_SND_HDA_POWER_SAVE
16762 if (!spec->loopback.amplist)
16763 spec->loopback.amplist = alc861vd_loopbacks;
16764#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016765
16766 return 0;
16767}
16768
16769/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016770 * ALC662 support
16771 *
16772 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16773 * configuration. Each pin widget can choose any input DACs and a mixer.
16774 * Each ADC is connected from a mixer of all inputs. This makes possible
16775 * 6-channel independent captures.
16776 *
16777 * In addition, an independent DAC for the multi-playback (not used in this
16778 * driver yet).
16779 */
16780#define ALC662_DIGOUT_NID 0x06
16781#define ALC662_DIGIN_NID 0x0a
16782
16783static hda_nid_t alc662_dac_nids[4] = {
16784 /* front, rear, clfe, rear_surr */
16785 0x02, 0x03, 0x04
16786};
16787
Kailang Yang622e84c2009-04-21 07:39:04 +020016788static hda_nid_t alc272_dac_nids[2] = {
16789 0x02, 0x03
16790};
16791
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016792static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016793 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016794 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016795};
Takashi Iwaie1406342008-02-11 18:32:32 +010016796
Kailang Yang622e84c2009-04-21 07:39:04 +020016797static hda_nid_t alc272_adc_nids[1] = {
16798 /* ADC1-2 */
16799 0x08,
16800};
16801
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016802static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016803static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16804
Takashi Iwaie1406342008-02-11 18:32:32 +010016805
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016806/* input MUX */
16807/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016808static struct hda_input_mux alc662_capture_source = {
16809 .num_items = 4,
16810 .items = {
16811 { "Mic", 0x0 },
16812 { "Front Mic", 0x1 },
16813 { "Line", 0x2 },
16814 { "CD", 0x4 },
16815 },
16816};
16817
16818static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16819 .num_items = 2,
16820 .items = {
16821 { "Mic", 0x1 },
16822 { "Line", 0x2 },
16823 },
16824};
Kailang Yang291702f2007-10-16 14:28:03 +020016825
Kailang Yang6dda9f42008-05-27 12:05:31 +020016826static struct hda_input_mux alc663_capture_source = {
16827 .num_items = 3,
16828 .items = {
16829 { "Mic", 0x0 },
16830 { "Front Mic", 0x1 },
16831 { "Line", 0x2 },
16832 },
16833};
16834
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016835#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016836static struct hda_input_mux alc272_nc10_capture_source = {
16837 .num_items = 16,
16838 .items = {
16839 { "Autoselect Mic", 0x0 },
16840 { "Internal Mic", 0x1 },
16841 { "In-0x02", 0x2 },
16842 { "In-0x03", 0x3 },
16843 { "In-0x04", 0x4 },
16844 { "In-0x05", 0x5 },
16845 { "In-0x06", 0x6 },
16846 { "In-0x07", 0x7 },
16847 { "In-0x08", 0x8 },
16848 { "In-0x09", 0x9 },
16849 { "In-0x0a", 0x0a },
16850 { "In-0x0b", 0x0b },
16851 { "In-0x0c", 0x0c },
16852 { "In-0x0d", 0x0d },
16853 { "In-0x0e", 0x0e },
16854 { "In-0x0f", 0x0f },
16855 },
16856};
16857#endif
16858
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016859/*
16860 * 2ch mode
16861 */
16862static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16863 { 2, NULL }
16864};
16865
16866/*
16867 * 2ch mode
16868 */
16869static struct hda_verb alc662_3ST_ch2_init[] = {
16870 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16871 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16872 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16873 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16874 { } /* end */
16875};
16876
16877/*
16878 * 6ch mode
16879 */
16880static struct hda_verb alc662_3ST_ch6_init[] = {
16881 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16882 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16883 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16884 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16885 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16886 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16887 { } /* end */
16888};
16889
16890static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16891 { 2, alc662_3ST_ch2_init },
16892 { 6, alc662_3ST_ch6_init },
16893};
16894
16895/*
16896 * 2ch mode
16897 */
16898static struct hda_verb alc662_sixstack_ch6_init[] = {
16899 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16900 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16901 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16902 { } /* end */
16903};
16904
16905/*
16906 * 6ch mode
16907 */
16908static struct hda_verb alc662_sixstack_ch8_init[] = {
16909 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16910 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16911 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16912 { } /* end */
16913};
16914
16915static struct hda_channel_mode alc662_5stack_modes[2] = {
16916 { 2, alc662_sixstack_ch6_init },
16917 { 6, alc662_sixstack_ch8_init },
16918};
16919
16920/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16921 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16922 */
16923
16924static struct snd_kcontrol_new alc662_base_mixer[] = {
16925 /* output mixer control */
16926 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016927 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016928 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016929 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016930 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16931 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016932 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16933 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016934 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16935
16936 /*Input mixer control */
16937 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16938 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16939 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16940 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16941 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16942 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16943 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16944 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016945 { } /* end */
16946};
16947
16948static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
16949 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016950 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016951 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16952 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16953 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16954 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16955 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16956 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16957 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16958 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16959 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016960 { } /* end */
16961};
16962
16963static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
16964 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016965 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016966 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016967 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016968 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16969 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016970 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16971 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016972 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16973 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16974 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16975 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16976 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16977 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16978 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16979 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16980 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016981 { } /* end */
16982};
16983
16984static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
16985 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16986 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010016987 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16988 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016989 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16990 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16991 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16992 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16993 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016994 { } /* end */
16995};
16996
Kailang Yang291702f2007-10-16 14:28:03 +020016997static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016998 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16999 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017000
17001 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17002 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17003 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17004
17005 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17006 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17007 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17008 { } /* end */
17009};
17010
Kailang Yang8c427222008-01-10 13:03:59 +010017011static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017012 ALC262_HIPPO_MASTER_SWITCH,
17013 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017014 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017015 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17016 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017017 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17018 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17019 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17020 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17021 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17022 { } /* end */
17023};
17024
Kailang Yangf1d4e282008-08-26 14:03:29 +020017025static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17026 .ops = &snd_hda_bind_vol,
17027 .values = {
17028 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17029 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17030 0
17031 },
17032};
17033
17034static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17035 .ops = &snd_hda_bind_sw,
17036 .values = {
17037 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17038 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17039 0
17040 },
17041};
17042
Kailang Yang6dda9f42008-05-27 12:05:31 +020017043static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017044 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17045 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17046 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17047 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17048 { } /* end */
17049};
17050
17051static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17052 .ops = &snd_hda_bind_sw,
17053 .values = {
17054 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17055 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17056 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17057 0
17058 },
17059};
17060
17061static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17062 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17063 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17064 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17065 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17066 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17067 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17068
17069 { } /* end */
17070};
17071
17072static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17073 .ops = &snd_hda_bind_sw,
17074 .values = {
17075 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17076 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17077 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17078 0
17079 },
17080};
17081
17082static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17083 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17084 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17085 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17086 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17087 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17088 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17089 { } /* end */
17090};
17091
17092static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017093 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17094 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017095 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17097 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17098 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17099 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17100 { } /* end */
17101};
17102
17103static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17104 .ops = &snd_hda_bind_vol,
17105 .values = {
17106 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17107 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17108 0
17109 },
17110};
17111
17112static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17113 .ops = &snd_hda_bind_sw,
17114 .values = {
17115 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17116 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17117 0
17118 },
17119};
17120
17121static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17122 HDA_BIND_VOL("Master Playback Volume",
17123 &alc663_asus_two_bind_master_vol),
17124 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17125 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017126 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17128 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017129 { } /* end */
17130};
17131
17132static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17133 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17134 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17135 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17136 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17137 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17138 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017139 { } /* end */
17140};
17141
17142static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17143 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17144 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17145 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17146 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17147 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17148
17149 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17150 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17151 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17152 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17153 { } /* end */
17154};
17155
17156static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17157 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17158 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17159 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17160
17161 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17162 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17163 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17164 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17165 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17166 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17167 { } /* end */
17168};
17169
Kailang Yangebb83ee2009-12-17 12:23:00 +010017170static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17171 .ops = &snd_hda_bind_sw,
17172 .values = {
17173 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17174 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17175 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17176 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17177 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17178 0
17179 },
17180};
17181
17182static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17183 .ops = &snd_hda_bind_sw,
17184 .values = {
17185 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17186 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17187 0
17188 },
17189};
17190
17191static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17192 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17193 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17194 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17195 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17196 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17197 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17198 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17199 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17200 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17201 { } /* end */
17202};
17203
17204static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17205 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17206 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17207 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17208 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17209 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17210 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17211 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17212 { } /* end */
17213};
17214
17215
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017216static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17217 {
17218 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17219 .name = "Channel Mode",
17220 .info = alc_ch_mode_info,
17221 .get = alc_ch_mode_get,
17222 .put = alc_ch_mode_put,
17223 },
17224 { } /* end */
17225};
17226
17227static struct hda_verb alc662_init_verbs[] = {
17228 /* ADC: mute amp left and right */
17229 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17230 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017231
Kailang Yangb60dd392007-09-20 12:50:29 +020017232 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17233 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17234 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17235 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17236 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17237 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017238
17239 /* Front Pin: output 0 (0x0c) */
17240 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17241 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17242
17243 /* Rear Pin: output 1 (0x0d) */
17244 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17245 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17246
17247 /* CLFE Pin: output 2 (0x0e) */
17248 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17249 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17250
17251 /* Mic (rear) pin: input vref at 80% */
17252 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17253 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17254 /* Front Mic pin: input vref at 80% */
17255 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17256 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17257 /* Line In pin: input */
17258 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17259 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17260 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17261 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17262 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17263 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17264 /* CD pin widget for input */
17265 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17266
17267 /* FIXME: use matrix-type input source selection */
17268 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17269 /* Input mixer */
17270 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017271 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017272
17273 /* always trun on EAPD */
17274 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17275 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17276
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017277 { }
17278};
17279
Kailang Yangcec27c82010-02-04 14:18:18 +010017280static struct hda_verb alc663_init_verbs[] = {
17281 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17282 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17283 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17284 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17285 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17286 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17287 { }
17288};
17289
17290static struct hda_verb alc272_init_verbs[] = {
17291 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17292 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17293 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17294 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17295 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17296 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17297 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17298 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17299 { }
17300};
17301
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017302static struct hda_verb alc662_sue_init_verbs[] = {
17303 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17304 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017305 {}
17306};
17307
17308static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17309 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17310 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17311 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017312};
17313
Kailang Yang8c427222008-01-10 13:03:59 +010017314/* Set Unsolicited Event*/
17315static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17316 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17317 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17318 {}
17319};
17320
Kailang Yang6dda9f42008-05-27 12:05:31 +020017321static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017322 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17323 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017324 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17325 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017326 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17327 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17328 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017329 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17330 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17331 {}
17332};
17333
Kailang Yangf1d4e282008-08-26 14:03:29 +020017334static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17335 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17336 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17337 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17338 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17339 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17340 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17341 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17342 {}
17343};
17344
17345static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17346 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17347 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17348 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17349 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17350 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17351 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17352 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17353 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17354 {}
17355};
17356
17357static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17358 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17359 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17360 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17361 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17362 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17363 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17364 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17365 {}
17366};
17367
17368static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17369 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17370 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17371 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17372 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17373 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17374 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17375 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17376 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17377 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17378 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17379 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17380 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17381 {}
17382};
17383
17384static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17385 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17386 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17387 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17388 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17389 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17390 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17391 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17392 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17393 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17394 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17395 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17396 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17397 {}
17398};
17399
Kailang Yang6dda9f42008-05-27 12:05:31 +020017400static struct hda_verb alc663_g71v_init_verbs[] = {
17401 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17402 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17403 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17404
17405 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17406 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17407 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17408
17409 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17410 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17411 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17412 {}
17413};
17414
17415static struct hda_verb alc663_g50v_init_verbs[] = {
17416 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17417 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17418 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17419
17420 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17421 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17422 {}
17423};
17424
Kailang Yangf1d4e282008-08-26 14:03:29 +020017425static struct hda_verb alc662_ecs_init_verbs[] = {
17426 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17427 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17428 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17429 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17430 {}
17431};
17432
Kailang Yang622e84c2009-04-21 07:39:04 +020017433static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17434 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17435 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17436 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17437 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17438 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17439 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17440 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17441 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17442 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17443 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17444 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17445 {}
17446};
17447
17448static struct hda_verb alc272_dell_init_verbs[] = {
17449 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17450 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17451 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17452 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17453 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17454 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17455 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17456 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17457 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17458 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17459 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17460 {}
17461};
17462
Kailang Yangebb83ee2009-12-17 12:23:00 +010017463static struct hda_verb alc663_mode7_init_verbs[] = {
17464 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17465 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17466 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17467 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17468 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17469 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17470 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17471 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17472 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17473 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17474 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17475 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17476 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17477 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17478 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17479 {}
17480};
17481
17482static struct hda_verb alc663_mode8_init_verbs[] = {
17483 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17484 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17485 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17486 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17487 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17488 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17489 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17490 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17491 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17492 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17493 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17494 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17495 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17496 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17497 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17498 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17499 {}
17500};
17501
Kailang Yangf1d4e282008-08-26 14:03:29 +020017502static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17503 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17504 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17505 { } /* end */
17506};
17507
Kailang Yang622e84c2009-04-21 07:39:04 +020017508static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17509 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17510 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17511 { } /* end */
17512};
17513
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017514static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17515{
17516 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017517 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017518
Wu Fengguang864f92b2009-11-18 12:38:02 +080017519 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017520 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017521
Takashi Iwai47fd8302007-08-10 17:11:07 +020017522 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17523 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017524}
17525
17526static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17527{
17528 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017529 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017530
Wu Fengguang864f92b2009-11-18 12:38:02 +080017531 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017532 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017533
Takashi Iwai47fd8302007-08-10 17:11:07 +020017534 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17535 HDA_AMP_MUTE, bits);
17536 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17537 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017538}
17539
17540static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17541 unsigned int res)
17542{
17543 if ((res >> 26) == ALC880_HP_EVENT)
17544 alc662_lenovo_101e_all_automute(codec);
17545 if ((res >> 26) == ALC880_FRONT_EVENT)
17546 alc662_lenovo_101e_ispeaker_automute(codec);
17547}
17548
Kailang Yang291702f2007-10-16 14:28:03 +020017549/* unsolicited event for HP jack sensing */
17550static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17551 unsigned int res)
17552{
Kailang Yang291702f2007-10-16 14:28:03 +020017553 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017554 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020017555 else
17556 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020017557}
17558
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017559static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017560{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017561 struct alc_spec *spec = codec->spec;
17562
17563 alc262_hippo1_setup(codec);
17564 spec->ext_mic.pin = 0x18;
17565 spec->ext_mic.mux_idx = 0;
17566 spec->int_mic.pin = 0x19;
17567 spec->int_mic.mux_idx = 1;
17568 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017569}
17570
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017571static void alc662_eeepc_inithook(struct hda_codec *codec)
17572{
17573 alc262_hippo_automute(codec);
17574 alc_mic_automute(codec);
17575}
17576
17577static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017578{
Takashi Iwai42171c12009-05-08 14:11:43 +020017579 struct alc_spec *spec = codec->spec;
17580
17581 spec->autocfg.hp_pins[0] = 0x14;
17582 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010017583}
17584
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017585#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
17586
Kailang Yang6dda9f42008-05-27 12:05:31 +020017587static void alc663_m51va_speaker_automute(struct hda_codec *codec)
17588{
17589 unsigned int present;
17590 unsigned char bits;
17591
Wu Fengguang864f92b2009-11-18 12:38:02 +080017592 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017593 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017594 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017595 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017596 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017597 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017598}
17599
17600static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
17601{
17602 unsigned int present;
17603 unsigned char bits;
17604
Wu Fengguang864f92b2009-11-18 12:38:02 +080017605 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017606 bits = present ? HDA_AMP_MUTE : 0;
17607 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017608 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017609 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017610 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017611 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017612 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017613 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017614 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017615}
17616
17617static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
17618{
17619 unsigned int present;
17620 unsigned char bits;
17621
Wu Fengguang864f92b2009-11-18 12:38:02 +080017622 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017623 bits = present ? HDA_AMP_MUTE : 0;
17624 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017625 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017626 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017627 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017628 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017629 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017630 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017631 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017632}
17633
17634static void alc662_f5z_speaker_automute(struct hda_codec *codec)
17635{
17636 unsigned int present;
17637 unsigned char bits;
17638
Wu Fengguang864f92b2009-11-18 12:38:02 +080017639 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017640 bits = present ? 0 : PIN_OUT;
17641 snd_hda_codec_write(codec, 0x14, 0,
17642 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
17643}
17644
17645static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
17646{
17647 unsigned int present1, present2;
17648
Wu Fengguang864f92b2009-11-18 12:38:02 +080017649 present1 = snd_hda_jack_detect(codec, 0x21);
17650 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017651
17652 if (present1 || present2) {
17653 snd_hda_codec_write_cache(codec, 0x14, 0,
17654 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17655 } else {
17656 snd_hda_codec_write_cache(codec, 0x14, 0,
17657 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17658 }
17659}
17660
17661static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
17662{
17663 unsigned int present1, present2;
17664
Wu Fengguang864f92b2009-11-18 12:38:02 +080017665 present1 = snd_hda_jack_detect(codec, 0x1b);
17666 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017667
17668 if (present1 || present2) {
17669 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017670 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017671 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017672 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017673 } else {
17674 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017675 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017676 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017677 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017678 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020017679}
17680
Kailang Yangebb83ee2009-12-17 12:23:00 +010017681static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
17682{
17683 unsigned int present1, present2;
17684
17685 present1 = snd_hda_codec_read(codec, 0x1b, 0,
17686 AC_VERB_GET_PIN_SENSE, 0)
17687 & AC_PINSENSE_PRESENCE;
17688 present2 = snd_hda_codec_read(codec, 0x21, 0,
17689 AC_VERB_GET_PIN_SENSE, 0)
17690 & AC_PINSENSE_PRESENCE;
17691
17692 if (present1 || present2) {
17693 snd_hda_codec_write_cache(codec, 0x14, 0,
17694 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17695 snd_hda_codec_write_cache(codec, 0x17, 0,
17696 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17697 } else {
17698 snd_hda_codec_write_cache(codec, 0x14, 0,
17699 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17700 snd_hda_codec_write_cache(codec, 0x17, 0,
17701 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17702 }
17703}
17704
17705static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
17706{
17707 unsigned int present1, present2;
17708
17709 present1 = snd_hda_codec_read(codec, 0x21, 0,
17710 AC_VERB_GET_PIN_SENSE, 0)
17711 & AC_PINSENSE_PRESENCE;
17712 present2 = snd_hda_codec_read(codec, 0x15, 0,
17713 AC_VERB_GET_PIN_SENSE, 0)
17714 & AC_PINSENSE_PRESENCE;
17715
17716 if (present1 || present2) {
17717 snd_hda_codec_write_cache(codec, 0x14, 0,
17718 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17719 snd_hda_codec_write_cache(codec, 0x17, 0,
17720 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17721 } else {
17722 snd_hda_codec_write_cache(codec, 0x14, 0,
17723 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17724 snd_hda_codec_write_cache(codec, 0x17, 0,
17725 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17726 }
17727}
17728
Kailang Yang6dda9f42008-05-27 12:05:31 +020017729static void alc663_m51va_unsol_event(struct hda_codec *codec,
17730 unsigned int res)
17731{
17732 switch (res >> 26) {
17733 case ALC880_HP_EVENT:
17734 alc663_m51va_speaker_automute(codec);
17735 break;
17736 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017737 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017738 break;
17739 }
17740}
17741
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017742static void alc663_m51va_setup(struct hda_codec *codec)
17743{
17744 struct alc_spec *spec = codec->spec;
17745 spec->ext_mic.pin = 0x18;
17746 spec->ext_mic.mux_idx = 0;
17747 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017748 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017749 spec->auto_mic = 1;
17750}
17751
Kailang Yang6dda9f42008-05-27 12:05:31 +020017752static void alc663_m51va_inithook(struct hda_codec *codec)
17753{
17754 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017755 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017756}
17757
Kailang Yangf1d4e282008-08-26 14:03:29 +020017758/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017759#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017760
17761static void alc663_mode1_setup(struct hda_codec *codec)
17762{
17763 struct alc_spec *spec = codec->spec;
17764 spec->ext_mic.pin = 0x18;
17765 spec->ext_mic.mux_idx = 0;
17766 spec->int_mic.pin = 0x19;
17767 spec->int_mic.mux_idx = 1;
17768 spec->auto_mic = 1;
17769}
17770
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017771#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017772
Kailang Yangf1d4e282008-08-26 14:03:29 +020017773/* ***************** Mode2 ******************************/
17774static void alc662_mode2_unsol_event(struct hda_codec *codec,
17775 unsigned int res)
17776{
17777 switch (res >> 26) {
17778 case ALC880_HP_EVENT:
17779 alc662_f5z_speaker_automute(codec);
17780 break;
17781 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017782 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017783 break;
17784 }
17785}
17786
Kailang Yangebb83ee2009-12-17 12:23:00 +010017787#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017788
Kailang Yangf1d4e282008-08-26 14:03:29 +020017789static void alc662_mode2_inithook(struct hda_codec *codec)
17790{
17791 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017792 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017793}
17794/* ***************** Mode3 ******************************/
17795static void alc663_mode3_unsol_event(struct hda_codec *codec,
17796 unsigned int res)
17797{
17798 switch (res >> 26) {
17799 case ALC880_HP_EVENT:
17800 alc663_two_hp_m1_speaker_automute(codec);
17801 break;
17802 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017803 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017804 break;
17805 }
17806}
17807
Kailang Yangebb83ee2009-12-17 12:23:00 +010017808#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017809
Kailang Yangf1d4e282008-08-26 14:03:29 +020017810static void alc663_mode3_inithook(struct hda_codec *codec)
17811{
17812 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017813 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017814}
17815/* ***************** Mode4 ******************************/
17816static void alc663_mode4_unsol_event(struct hda_codec *codec,
17817 unsigned int res)
17818{
17819 switch (res >> 26) {
17820 case ALC880_HP_EVENT:
17821 alc663_21jd_two_speaker_automute(codec);
17822 break;
17823 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017824 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017825 break;
17826 }
17827}
17828
Kailang Yangebb83ee2009-12-17 12:23:00 +010017829#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017830
Kailang Yangf1d4e282008-08-26 14:03:29 +020017831static void alc663_mode4_inithook(struct hda_codec *codec)
17832{
17833 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017834 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017835}
17836/* ***************** Mode5 ******************************/
17837static void alc663_mode5_unsol_event(struct hda_codec *codec,
17838 unsigned int res)
17839{
17840 switch (res >> 26) {
17841 case ALC880_HP_EVENT:
17842 alc663_15jd_two_speaker_automute(codec);
17843 break;
17844 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017845 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017846 break;
17847 }
17848}
17849
Kailang Yangebb83ee2009-12-17 12:23:00 +010017850#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017851
Kailang Yangf1d4e282008-08-26 14:03:29 +020017852static void alc663_mode5_inithook(struct hda_codec *codec)
17853{
17854 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017855 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017856}
17857/* ***************** Mode6 ******************************/
17858static void alc663_mode6_unsol_event(struct hda_codec *codec,
17859 unsigned int res)
17860{
17861 switch (res >> 26) {
17862 case ALC880_HP_EVENT:
17863 alc663_two_hp_m2_speaker_automute(codec);
17864 break;
17865 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017866 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017867 break;
17868 }
17869}
17870
Kailang Yangebb83ee2009-12-17 12:23:00 +010017871#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017872
Kailang Yangf1d4e282008-08-26 14:03:29 +020017873static void alc663_mode6_inithook(struct hda_codec *codec)
17874{
17875 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017876 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017877}
17878
Kailang Yangebb83ee2009-12-17 12:23:00 +010017879/* ***************** Mode7 ******************************/
17880static void alc663_mode7_unsol_event(struct hda_codec *codec,
17881 unsigned int res)
17882{
17883 switch (res >> 26) {
17884 case ALC880_HP_EVENT:
17885 alc663_two_hp_m7_speaker_automute(codec);
17886 break;
17887 case ALC880_MIC_EVENT:
17888 alc_mic_automute(codec);
17889 break;
17890 }
17891}
17892
17893#define alc663_mode7_setup alc663_mode1_setup
17894
17895static void alc663_mode7_inithook(struct hda_codec *codec)
17896{
17897 alc663_two_hp_m7_speaker_automute(codec);
17898 alc_mic_automute(codec);
17899}
17900
17901/* ***************** Mode8 ******************************/
17902static void alc663_mode8_unsol_event(struct hda_codec *codec,
17903 unsigned int res)
17904{
17905 switch (res >> 26) {
17906 case ALC880_HP_EVENT:
17907 alc663_two_hp_m8_speaker_automute(codec);
17908 break;
17909 case ALC880_MIC_EVENT:
17910 alc_mic_automute(codec);
17911 break;
17912 }
17913}
17914
17915#define alc663_mode8_setup alc663_m51va_setup
17916
17917static void alc663_mode8_inithook(struct hda_codec *codec)
17918{
17919 alc663_two_hp_m8_speaker_automute(codec);
17920 alc_mic_automute(codec);
17921}
17922
Kailang Yang6dda9f42008-05-27 12:05:31 +020017923static void alc663_g71v_hp_automute(struct hda_codec *codec)
17924{
17925 unsigned int present;
17926 unsigned char bits;
17927
Wu Fengguang864f92b2009-11-18 12:38:02 +080017928 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017929 bits = present ? HDA_AMP_MUTE : 0;
17930 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17931 HDA_AMP_MUTE, bits);
17932 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17933 HDA_AMP_MUTE, bits);
17934}
17935
17936static void alc663_g71v_front_automute(struct hda_codec *codec)
17937{
17938 unsigned int present;
17939 unsigned char bits;
17940
Wu Fengguang864f92b2009-11-18 12:38:02 +080017941 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017942 bits = present ? HDA_AMP_MUTE : 0;
17943 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17944 HDA_AMP_MUTE, bits);
17945}
17946
17947static void alc663_g71v_unsol_event(struct hda_codec *codec,
17948 unsigned int res)
17949{
17950 switch (res >> 26) {
17951 case ALC880_HP_EVENT:
17952 alc663_g71v_hp_automute(codec);
17953 break;
17954 case ALC880_FRONT_EVENT:
17955 alc663_g71v_front_automute(codec);
17956 break;
17957 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017958 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017959 break;
17960 }
17961}
17962
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017963#define alc663_g71v_setup alc663_m51va_setup
17964
Kailang Yang6dda9f42008-05-27 12:05:31 +020017965static void alc663_g71v_inithook(struct hda_codec *codec)
17966{
17967 alc663_g71v_front_automute(codec);
17968 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017969 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017970}
17971
17972static void alc663_g50v_unsol_event(struct hda_codec *codec,
17973 unsigned int res)
17974{
17975 switch (res >> 26) {
17976 case ALC880_HP_EVENT:
17977 alc663_m51va_speaker_automute(codec);
17978 break;
17979 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017980 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017981 break;
17982 }
17983}
17984
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017985#define alc663_g50v_setup alc663_m51va_setup
17986
Kailang Yang6dda9f42008-05-27 12:05:31 +020017987static void alc663_g50v_inithook(struct hda_codec *codec)
17988{
17989 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017990 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017991}
17992
Kailang Yangf1d4e282008-08-26 14:03:29 +020017993static struct snd_kcontrol_new alc662_ecs_mixer[] = {
17994 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020017995 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017996
17997 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
17998 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
17999 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18000
18001 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18002 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18003 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18004 { } /* end */
18005};
18006
Chris Pockelé9541ba12009-05-12 08:08:53 +020018007static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18008 /* Master Playback automatically created from Speaker and Headphone */
18009 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18010 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18011 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18012 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18013
18014 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18015 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18016 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18017
18018 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18019 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18020 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18021 { } /* end */
18022};
18023
Takashi Iwaicb53c622007-08-10 17:21:45 +020018024#ifdef CONFIG_SND_HDA_POWER_SAVE
18025#define alc662_loopbacks alc880_loopbacks
18026#endif
18027
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018028
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018029/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018030#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18031#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18032#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18033#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18034
18035/*
18036 * configuration and preset
18037 */
18038static const char *alc662_models[ALC662_MODEL_LAST] = {
18039 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18040 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18041 [ALC662_3ST_6ch] = "3stack-6ch",
18042 [ALC662_5ST_DIG] = "6stack-dig",
18043 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018044 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018045 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018046 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018047 [ALC663_ASUS_M51VA] = "m51va",
18048 [ALC663_ASUS_G71V] = "g71v",
18049 [ALC663_ASUS_H13] = "h13",
18050 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018051 [ALC663_ASUS_MODE1] = "asus-mode1",
18052 [ALC662_ASUS_MODE2] = "asus-mode2",
18053 [ALC663_ASUS_MODE3] = "asus-mode3",
18054 [ALC663_ASUS_MODE4] = "asus-mode4",
18055 [ALC663_ASUS_MODE5] = "asus-mode5",
18056 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018057 [ALC663_ASUS_MODE7] = "asus-mode7",
18058 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018059 [ALC272_DELL] = "dell",
18060 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018061 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018062 [ALC662_AUTO] = "auto",
18063};
18064
18065static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018066 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018067 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18068 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018069 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18070 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018071 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018072 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18073 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18074 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18075 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018076 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18077 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018078 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018079 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18080 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18081 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18082 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18083 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018084 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018085 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18086 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018087 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18088 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18089 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18090 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018091 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018092 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18093 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18094 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018095 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18096 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18097 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18098 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018099 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018100 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18101 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018102 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018103 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18104 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18105 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018106 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018107 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018108 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18109 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018110 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18111 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18112 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018113 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018114 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18115 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018116 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018117 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018118 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018119 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18120 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18121 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018122 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018123 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18124 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018125 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018126 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018127 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018128 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018129 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18130 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018131 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018132 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018133 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18134 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018135 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018136 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018137 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018138 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018139 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018140 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018141 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18142 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018143 {}
18144};
18145
18146static struct alc_config_preset alc662_presets[] = {
18147 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018148 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018149 .init_verbs = { alc662_init_verbs },
18150 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18151 .dac_nids = alc662_dac_nids,
18152 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018153 .dig_in_nid = ALC662_DIGIN_NID,
18154 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18155 .channel_mode = alc662_3ST_2ch_modes,
18156 .input_mux = &alc662_capture_source,
18157 },
18158 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018159 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018160 .init_verbs = { alc662_init_verbs },
18161 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18162 .dac_nids = alc662_dac_nids,
18163 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018164 .dig_in_nid = ALC662_DIGIN_NID,
18165 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18166 .channel_mode = alc662_3ST_6ch_modes,
18167 .need_dac_fix = 1,
18168 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018169 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018170 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018171 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018172 .init_verbs = { alc662_init_verbs },
18173 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18174 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018175 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18176 .channel_mode = alc662_3ST_6ch_modes,
18177 .need_dac_fix = 1,
18178 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018179 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018180 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018181 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018182 .init_verbs = { alc662_init_verbs },
18183 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18184 .dac_nids = alc662_dac_nids,
18185 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018186 .dig_in_nid = ALC662_DIGIN_NID,
18187 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18188 .channel_mode = alc662_5stack_modes,
18189 .input_mux = &alc662_capture_source,
18190 },
18191 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018192 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018193 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18194 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18195 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018196 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18197 .channel_mode = alc662_3ST_2ch_modes,
18198 .input_mux = &alc662_lenovo_101e_capture_source,
18199 .unsol_event = alc662_lenovo_101e_unsol_event,
18200 .init_hook = alc662_lenovo_101e_all_automute,
18201 },
Kailang Yang291702f2007-10-16 14:28:03 +020018202 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018203 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018204 .init_verbs = { alc662_init_verbs,
18205 alc662_eeepc_sue_init_verbs },
18206 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18207 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018208 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18209 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018210 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018211 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018212 .init_hook = alc662_eeepc_inithook,
18213 },
Kailang Yang8c427222008-01-10 13:03:59 +010018214 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018215 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018216 alc662_chmode_mixer },
18217 .init_verbs = { alc662_init_verbs,
18218 alc662_eeepc_ep20_sue_init_verbs },
18219 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18220 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018221 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18222 .channel_mode = alc662_3ST_6ch_modes,
18223 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018224 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018225 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018226 .init_hook = alc662_eeepc_ep20_inithook,
18227 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018228 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018229 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018230 .init_verbs = { alc662_init_verbs,
18231 alc662_ecs_init_verbs },
18232 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18233 .dac_nids = alc662_dac_nids,
18234 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18235 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018236 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018237 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018238 .init_hook = alc662_eeepc_inithook,
18239 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018240 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018241 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018242 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18243 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18244 .dac_nids = alc662_dac_nids,
18245 .dig_out_nid = ALC662_DIGOUT_NID,
18246 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18247 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018248 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018249 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018250 .init_hook = alc663_m51va_inithook,
18251 },
18252 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018253 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018254 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18255 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18256 .dac_nids = alc662_dac_nids,
18257 .dig_out_nid = ALC662_DIGOUT_NID,
18258 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18259 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018260 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018261 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018262 .init_hook = alc663_g71v_inithook,
18263 },
18264 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018265 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018266 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18267 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18268 .dac_nids = alc662_dac_nids,
18269 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18270 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018271 .unsol_event = alc663_m51va_unsol_event,
18272 .init_hook = alc663_m51va_inithook,
18273 },
18274 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018275 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018276 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18277 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18278 .dac_nids = alc662_dac_nids,
18279 .dig_out_nid = ALC662_DIGOUT_NID,
18280 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18281 .channel_mode = alc662_3ST_6ch_modes,
18282 .input_mux = &alc663_capture_source,
18283 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018284 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018285 .init_hook = alc663_g50v_inithook,
18286 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018287 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018288 .mixers = { alc663_m51va_mixer },
18289 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290 .init_verbs = { alc662_init_verbs,
18291 alc663_21jd_amic_init_verbs },
18292 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18293 .hp_nid = 0x03,
18294 .dac_nids = alc662_dac_nids,
18295 .dig_out_nid = ALC662_DIGOUT_NID,
18296 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18297 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018298 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018299 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018300 .init_hook = alc663_mode1_inithook,
18301 },
18302 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018303 .mixers = { alc662_1bjd_mixer },
18304 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018305 .init_verbs = { alc662_init_verbs,
18306 alc662_1bjd_amic_init_verbs },
18307 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18308 .dac_nids = alc662_dac_nids,
18309 .dig_out_nid = ALC662_DIGOUT_NID,
18310 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18311 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018312 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018313 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018314 .init_hook = alc662_mode2_inithook,
18315 },
18316 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018317 .mixers = { alc663_two_hp_m1_mixer },
18318 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018319 .init_verbs = { alc662_init_verbs,
18320 alc663_two_hp_amic_m1_init_verbs },
18321 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18322 .hp_nid = 0x03,
18323 .dac_nids = alc662_dac_nids,
18324 .dig_out_nid = ALC662_DIGOUT_NID,
18325 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18326 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018327 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018328 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018329 .init_hook = alc663_mode3_inithook,
18330 },
18331 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018332 .mixers = { alc663_asus_21jd_clfe_mixer },
18333 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018334 .init_verbs = { alc662_init_verbs,
18335 alc663_21jd_amic_init_verbs},
18336 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18337 .hp_nid = 0x03,
18338 .dac_nids = alc662_dac_nids,
18339 .dig_out_nid = ALC662_DIGOUT_NID,
18340 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18341 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018342 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018343 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018344 .init_hook = alc663_mode4_inithook,
18345 },
18346 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018347 .mixers = { alc663_asus_15jd_clfe_mixer },
18348 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018349 .init_verbs = { alc662_init_verbs,
18350 alc663_15jd_amic_init_verbs },
18351 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18352 .hp_nid = 0x03,
18353 .dac_nids = alc662_dac_nids,
18354 .dig_out_nid = ALC662_DIGOUT_NID,
18355 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18356 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018357 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018358 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018359 .init_hook = alc663_mode5_inithook,
18360 },
18361 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018362 .mixers = { alc663_two_hp_m2_mixer },
18363 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018364 .init_verbs = { alc662_init_verbs,
18365 alc663_two_hp_amic_m2_init_verbs },
18366 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18367 .hp_nid = 0x03,
18368 .dac_nids = alc662_dac_nids,
18369 .dig_out_nid = ALC662_DIGOUT_NID,
18370 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18371 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018372 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018373 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018374 .init_hook = alc663_mode6_inithook,
18375 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018376 [ALC663_ASUS_MODE7] = {
18377 .mixers = { alc663_mode7_mixer },
18378 .cap_mixer = alc662_auto_capture_mixer,
18379 .init_verbs = { alc662_init_verbs,
18380 alc663_mode7_init_verbs },
18381 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18382 .hp_nid = 0x03,
18383 .dac_nids = alc662_dac_nids,
18384 .dig_out_nid = ALC662_DIGOUT_NID,
18385 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18386 .channel_mode = alc662_3ST_2ch_modes,
18387 .unsol_event = alc663_mode7_unsol_event,
18388 .setup = alc663_mode7_setup,
18389 .init_hook = alc663_mode7_inithook,
18390 },
18391 [ALC663_ASUS_MODE8] = {
18392 .mixers = { alc663_mode8_mixer },
18393 .cap_mixer = alc662_auto_capture_mixer,
18394 .init_verbs = { alc662_init_verbs,
18395 alc663_mode8_init_verbs },
18396 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18397 .hp_nid = 0x03,
18398 .dac_nids = alc662_dac_nids,
18399 .dig_out_nid = ALC662_DIGOUT_NID,
18400 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18401 .channel_mode = alc662_3ST_2ch_modes,
18402 .unsol_event = alc663_mode8_unsol_event,
18403 .setup = alc663_mode8_setup,
18404 .init_hook = alc663_mode8_inithook,
18405 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018406 [ALC272_DELL] = {
18407 .mixers = { alc663_m51va_mixer },
18408 .cap_mixer = alc272_auto_capture_mixer,
18409 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18410 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18411 .dac_nids = alc662_dac_nids,
18412 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18413 .adc_nids = alc272_adc_nids,
18414 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18415 .capsrc_nids = alc272_capsrc_nids,
18416 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018417 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018418 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018419 .init_hook = alc663_m51va_inithook,
18420 },
18421 [ALC272_DELL_ZM1] = {
18422 .mixers = { alc663_m51va_mixer },
18423 .cap_mixer = alc662_auto_capture_mixer,
18424 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18425 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18426 .dac_nids = alc662_dac_nids,
18427 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18428 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018429 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018430 .capsrc_nids = alc662_capsrc_nids,
18431 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018432 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018433 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018434 .init_hook = alc663_m51va_inithook,
18435 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018436 [ALC272_SAMSUNG_NC10] = {
18437 .mixers = { alc272_nc10_mixer },
18438 .init_verbs = { alc662_init_verbs,
18439 alc663_21jd_amic_init_verbs },
18440 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18441 .dac_nids = alc272_dac_nids,
18442 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18443 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018444 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018445 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018446 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018447 .init_hook = alc663_mode4_inithook,
18448 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018449};
18450
18451
18452/*
18453 * BIOS auto configuration
18454 */
18455
Takashi Iwai7085ec12009-10-02 09:03:58 +020018456/* convert from MIX nid to DAC */
18457static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18458{
18459 if (nid == 0x0f)
18460 return 0x02;
18461 else if (nid >= 0x0c && nid <= 0x0e)
18462 return nid - 0x0c + 0x02;
18463 else
18464 return 0;
18465}
18466
18467/* get MIX nid connected to the given pin targeted to DAC */
18468static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18469 hda_nid_t dac)
18470{
18471 hda_nid_t mix[4];
18472 int i, num;
18473
18474 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18475 for (i = 0; i < num; i++) {
18476 if (alc662_mix_to_dac(mix[i]) == dac)
18477 return mix[i];
18478 }
18479 return 0;
18480}
18481
18482/* look for an empty DAC slot */
18483static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18484{
18485 struct alc_spec *spec = codec->spec;
18486 hda_nid_t srcs[5];
18487 int i, j, num;
18488
18489 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18490 if (num < 0)
18491 return 0;
18492 for (i = 0; i < num; i++) {
18493 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18494 if (!nid)
18495 continue;
18496 for (j = 0; j < spec->multiout.num_dacs; j++)
18497 if (spec->multiout.dac_nids[j] == nid)
18498 break;
18499 if (j >= spec->multiout.num_dacs)
18500 return nid;
18501 }
18502 return 0;
18503}
18504
18505/* fill in the dac_nids table from the parsed pin configuration */
18506static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18507 const struct auto_pin_cfg *cfg)
18508{
18509 struct alc_spec *spec = codec->spec;
18510 int i;
18511 hda_nid_t dac;
18512
18513 spec->multiout.dac_nids = spec->private_dac_nids;
18514 for (i = 0; i < cfg->line_outs; i++) {
18515 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18516 if (!dac)
18517 continue;
18518 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18519 }
18520 return 0;
18521}
18522
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018523static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018524 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018525{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018526 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018527 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18528}
18529
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018530static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018531 hda_nid_t nid, unsigned int chs)
18532{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018533 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018534 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18535}
18536
18537#define alc662_add_stereo_vol(spec, pfx, nid) \
18538 alc662_add_vol_ctl(spec, pfx, nid, 3)
18539#define alc662_add_stereo_sw(spec, pfx, nid) \
18540 alc662_add_sw_ctl(spec, pfx, nid, 3)
18541
18542/* add playback controls from the parsed DAC table */
18543static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18544 const struct auto_pin_cfg *cfg)
18545{
18546 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018547 static const char *chname[4] = {
18548 "Front", "Surround", NULL /*CLFE*/, "Side"
18549 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018550 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018551 int i, err;
18552
18553 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018554 nid = spec->multiout.dac_nids[i];
18555 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018556 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018557 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
18558 if (!mix)
18559 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018560 if (i == 2) {
18561 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018562 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018563 if (err < 0)
18564 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018565 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018566 if (err < 0)
18567 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018568 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018569 if (err < 0)
18570 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018571 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018572 if (err < 0)
18573 return err;
18574 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018575 const char *pfx;
18576 if (cfg->line_outs == 1 &&
18577 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018578 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018579 pfx = "Speaker";
18580 else
18581 pfx = "PCM";
18582 } else
18583 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018584 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018585 if (err < 0)
18586 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018587 if (cfg->line_outs == 1 &&
18588 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
18589 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020018590 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018591 if (err < 0)
18592 return err;
18593 }
18594 }
18595 return 0;
18596}
18597
18598/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018599/* return DAC nid if any new DAC is assigned */
18600static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018601 const char *pfx)
18602{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018603 struct alc_spec *spec = codec->spec;
18604 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018605 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018606
18607 if (!pin)
18608 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018609 nid = alc662_look_for_dac(codec, pin);
18610 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018611 /* the corresponding DAC is already occupied */
18612 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18613 return 0; /* no way */
18614 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018615 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018616 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18617 }
18618
18619 mix = alc662_dac_to_mix(codec, pin, nid);
18620 if (!mix)
18621 return 0;
18622 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
18623 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018624 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018625 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
18626 if (err < 0)
18627 return err;
18628 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018629}
18630
18631/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018632#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018633 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018634
18635static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
18636 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018637 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018638{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018639 int i, num;
18640 hda_nid_t srcs[4];
18641
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018642 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018643 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018644 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
18645 if (num <= 1)
18646 return;
18647 for (i = 0; i < num; i++) {
18648 if (alc662_mix_to_dac(srcs[i]) != dac)
18649 continue;
18650 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18651 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018652 }
18653}
18654
18655static void alc662_auto_init_multi_out(struct hda_codec *codec)
18656{
18657 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018658 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018659 int i;
18660
18661 for (i = 0; i <= HDA_SIDE; i++) {
18662 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18663 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020018664 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018665 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018666 }
18667}
18668
18669static void alc662_auto_init_hp_out(struct hda_codec *codec)
18670{
18671 struct alc_spec *spec = codec->spec;
18672 hda_nid_t pin;
18673
18674 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018675 if (pin)
18676 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
18677 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018678 pin = spec->autocfg.speaker_pins[0];
18679 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018680 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
18681 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018682}
18683
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018684#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
18685
18686static void alc662_auto_init_analog_input(struct hda_codec *codec)
18687{
18688 struct alc_spec *spec = codec->spec;
18689 int i;
18690
18691 for (i = 0; i < AUTO_PIN_LAST; i++) {
18692 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020018693 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010018694 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010018695 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010018696 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018697 snd_hda_codec_write(codec, nid, 0,
18698 AC_VERB_SET_AMP_GAIN_MUTE,
18699 AMP_OUT_MUTE);
18700 }
18701 }
18702}
18703
Takashi Iwaif511b012008-08-15 16:46:42 +020018704#define alc662_auto_init_input_src alc882_auto_init_input_src
18705
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018706static int alc662_parse_auto_config(struct hda_codec *codec)
18707{
18708 struct alc_spec *spec = codec->spec;
18709 int err;
18710 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
18711
18712 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18713 alc662_ignore);
18714 if (err < 0)
18715 return err;
18716 if (!spec->autocfg.line_outs)
18717 return 0; /* can't find valid BIOS pin config */
18718
Takashi Iwai7085ec12009-10-02 09:03:58 +020018719 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018720 if (err < 0)
18721 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018722 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018723 if (err < 0)
18724 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018725 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018726 spec->autocfg.speaker_pins[0],
18727 "Speaker");
18728 if (err < 0)
18729 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018730 if (err)
18731 spec->multiout.extra_out_nid[0] = err;
18732 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018733 "Headphone");
18734 if (err < 0)
18735 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018736 if (err)
18737 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018738 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018739 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018740 return err;
18741
18742 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18743
Takashi Iwai0852d7a2009-02-11 11:35:15 +010018744 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018745 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
18746
Takashi Iwai603c4012008-07-30 15:01:44 +020018747 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018748 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018749
18750 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018751 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018752
Kailang Yangcec27c82010-02-04 14:18:18 +010018753 add_verb(spec, alc662_init_verbs);
18754 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018755 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010018756 add_verb(spec, alc663_init_verbs);
18757
18758 if (codec->vendor_id == 0x10ec0272)
18759 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018760
18761 err = alc_auto_add_mic_boost(codec);
18762 if (err < 0)
18763 return err;
18764
Kailang Yang6227cdc2010-02-25 08:36:52 +010018765 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18766 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18767 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18768 else
18769 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018770
Takashi Iwai8c872862007-06-19 12:11:16 +020018771 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018772}
18773
18774/* additional initialization for auto-configuration model */
18775static void alc662_auto_init(struct hda_codec *codec)
18776{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018777 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018778 alc662_auto_init_multi_out(codec);
18779 alc662_auto_init_hp_out(codec);
18780 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018781 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018782 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018783 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018784}
18785
18786static int patch_alc662(struct hda_codec *codec)
18787{
18788 struct alc_spec *spec;
18789 int err, board_config;
18790
18791 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18792 if (!spec)
18793 return -ENOMEM;
18794
18795 codec->spec = spec;
18796
Kailang Yangda00c242010-03-19 11:23:45 +010018797 alc_auto_parse_customize_define(codec);
18798
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018799 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18800
Kailang Yangc027ddc2010-03-19 11:33:06 +010018801 if (alc_read_coef_idx(codec, 0) == 0x8020)
18802 alc_codec_rename(codec, "ALC661");
18803 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
18804 codec->bus->pci->subsystem_vendor == 0x1025 &&
18805 spec->cdefine.platform_type == 1)
18806 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010018807
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018808 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18809 alc662_models,
18810 alc662_cfg_tbl);
18811 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018812 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18813 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018814 board_config = ALC662_AUTO;
18815 }
18816
18817 if (board_config == ALC662_AUTO) {
18818 /* automatic parse from the BIOS config */
18819 err = alc662_parse_auto_config(codec);
18820 if (err < 0) {
18821 alc_free(codec);
18822 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018823 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018824 printk(KERN_INFO
18825 "hda_codec: Cannot set up configuration "
18826 "from BIOS. Using base mode...\n");
18827 board_config = ALC662_3ST_2ch_DIG;
18828 }
18829 }
18830
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018831 err = snd_hda_attach_beep_device(codec, 0x1);
18832 if (err < 0) {
18833 alc_free(codec);
18834 return err;
18835 }
18836
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018837 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018838 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018839
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018840 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18841 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18842
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018843 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18844 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18845
Takashi Iwaidd704692009-08-11 08:45:11 +020018846 if (!spec->adc_nids) {
18847 spec->adc_nids = alc662_adc_nids;
18848 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18849 }
18850 if (!spec->capsrc_nids)
18851 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018852
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018853 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018854 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018855
Kailang Yangda00c242010-03-19 11:23:45 +010018856 if (spec->cdefine.enable_pcbeep) {
18857 switch (codec->vendor_id) {
18858 case 0x10ec0662:
18859 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18860 break;
18861 case 0x10ec0272:
18862 case 0x10ec0663:
18863 case 0x10ec0665:
18864 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18865 break;
18866 case 0x10ec0273:
18867 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18868 break;
18869 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018870 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018871 spec->vmaster_nid = 0x02;
18872
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018873 codec->patch_ops = alc_patch_ops;
18874 if (board_config == ALC662_AUTO)
18875 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018876#ifdef CONFIG_SND_HDA_POWER_SAVE
18877 if (!spec->loopback.amplist)
18878 spec->loopback.amplist = alc662_loopbacks;
18879#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018880
18881 return 0;
18882}
18883
Kailang Yang274693f2009-12-03 10:07:50 +010018884static int patch_alc888(struct hda_codec *codec)
18885{
18886 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18887 kfree(codec->chip_name);
18888 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018889 if (!codec->chip_name) {
18890 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018891 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018892 }
18893 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018894 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018895 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018896}
18897
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018898/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018899 * ALC680 support
18900 */
18901#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
18902#define alc680_modes alc260_modes
18903
18904static hda_nid_t alc680_dac_nids[3] = {
18905 /* Lout1, Lout2, hp */
18906 0x02, 0x03, 0x04
18907};
18908
18909static hda_nid_t alc680_adc_nids[3] = {
18910 /* ADC0-2 */
18911 /* DMIC, MIC, Line-in*/
18912 0x07, 0x08, 0x09
18913};
18914
18915static struct snd_kcontrol_new alc680_base_mixer[] = {
18916 /* output mixer control */
18917 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
18918 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18919 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
18920 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
18921 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
18922 { }
18923};
18924
18925static struct snd_kcontrol_new alc680_capture_mixer[] = {
18926 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
18927 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
18928 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
18929 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
18930 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
18931 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
18932 { } /* end */
18933};
18934
18935/*
18936 * generic initialization of ADC, input mixers and output mixers
18937 */
18938static struct hda_verb alc680_init_verbs[] = {
18939 /* Unmute DAC0-1 and set vol = 0 */
18940 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18941 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18942 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18943
18944 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
18945 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
18946 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
18947 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
18948 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
18949
18950 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
18951 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
18952 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
18953 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
18954 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
18955 { }
18956};
18957
18958/* create input playback/capture controls for the given pin */
18959static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
18960 const char *ctlname, int idx)
18961{
18962 hda_nid_t dac;
18963 int err;
18964
18965 switch (nid) {
18966 case 0x14:
18967 dac = 0x02;
18968 break;
18969 case 0x15:
18970 dac = 0x03;
18971 break;
18972 case 0x16:
18973 dac = 0x04;
18974 break;
18975 default:
18976 return 0;
18977 }
18978 if (spec->multiout.dac_nids[0] != dac &&
18979 spec->multiout.dac_nids[1] != dac) {
18980 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
18981 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
18982 HDA_OUTPUT));
18983 if (err < 0)
18984 return err;
18985
18986 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
18987 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
18988
18989 if (err < 0)
18990 return err;
18991 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18992 }
18993
18994 return 0;
18995}
18996
18997/* add playback controls from the parsed DAC table */
18998static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
18999 const struct auto_pin_cfg *cfg)
19000{
19001 hda_nid_t nid;
19002 int err;
19003
19004 spec->multiout.dac_nids = spec->private_dac_nids;
19005
19006 nid = cfg->line_out_pins[0];
19007 if (nid) {
19008 const char *name;
19009 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19010 name = "Speaker";
19011 else
19012 name = "Front";
19013 err = alc680_new_analog_output(spec, nid, name, 0);
19014 if (err < 0)
19015 return err;
19016 }
19017
19018 nid = cfg->speaker_pins[0];
19019 if (nid) {
19020 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19021 if (err < 0)
19022 return err;
19023 }
19024 nid = cfg->hp_pins[0];
19025 if (nid) {
19026 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19027 if (err < 0)
19028 return err;
19029 }
19030
19031 return 0;
19032}
19033
19034static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19035 hda_nid_t nid, int pin_type)
19036{
19037 alc_set_pin_output(codec, nid, pin_type);
19038}
19039
19040static void alc680_auto_init_multi_out(struct hda_codec *codec)
19041{
19042 struct alc_spec *spec = codec->spec;
19043 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19044 if (nid) {
19045 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19046 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19047 }
19048}
19049
19050static void alc680_auto_init_hp_out(struct hda_codec *codec)
19051{
19052 struct alc_spec *spec = codec->spec;
19053 hda_nid_t pin;
19054
19055 pin = spec->autocfg.hp_pins[0];
19056 if (pin)
19057 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19058 pin = spec->autocfg.speaker_pins[0];
19059 if (pin)
19060 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19061}
19062
19063/* pcm configuration: identical with ALC880 */
19064#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19065#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19066#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19067#define alc680_pcm_digital_playback alc880_pcm_digital_playback
19068
19069static struct hda_input_mux alc680_capture_source = {
19070 .num_items = 1,
19071 .items = {
19072 { "Mic", 0x0 },
19073 },
19074};
19075
19076/*
19077 * BIOS auto configuration
19078 */
19079static int alc680_parse_auto_config(struct hda_codec *codec)
19080{
19081 struct alc_spec *spec = codec->spec;
19082 int err;
19083 static hda_nid_t alc680_ignore[] = { 0 };
19084
19085 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19086 alc680_ignore);
19087 if (err < 0)
19088 return err;
19089 if (!spec->autocfg.line_outs) {
19090 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19091 spec->multiout.max_channels = 2;
19092 spec->no_analog = 1;
19093 goto dig_only;
19094 }
19095 return 0; /* can't find valid BIOS pin config */
19096 }
19097 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19098 if (err < 0)
19099 return err;
19100
19101 spec->multiout.max_channels = 2;
19102
19103 dig_only:
19104 /* digital only support output */
19105 if (spec->autocfg.dig_outs) {
19106 spec->multiout.dig_out_nid = ALC680_DIGOUT_NID;
19107 spec->dig_out_type = spec->autocfg.dig_out_type[0];
19108 }
19109 if (spec->kctls.list)
19110 add_mixer(spec, spec->kctls.list);
19111
19112 add_verb(spec, alc680_init_verbs);
19113 spec->num_mux_defs = 1;
19114 spec->input_mux = &alc680_capture_source;
19115
19116 err = alc_auto_add_mic_boost(codec);
19117 if (err < 0)
19118 return err;
19119
19120 return 1;
19121}
19122
19123#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19124
19125/* init callback for auto-configuration model -- overriding the default init */
19126static void alc680_auto_init(struct hda_codec *codec)
19127{
19128 struct alc_spec *spec = codec->spec;
19129 alc680_auto_init_multi_out(codec);
19130 alc680_auto_init_hp_out(codec);
19131 alc680_auto_init_analog_input(codec);
19132 if (spec->unsol_event)
19133 alc_inithook(codec);
19134}
19135
19136/*
19137 * configuration and preset
19138 */
19139static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019140 [ALC680_BASE] = "base",
19141 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019142};
19143
19144static struct snd_pci_quirk alc680_cfg_tbl[] = {
19145 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19146 {}
19147};
19148
19149static struct alc_config_preset alc680_presets[] = {
19150 [ALC680_BASE] = {
19151 .mixers = { alc680_base_mixer },
19152 .cap_mixer = alc680_capture_mixer,
19153 .init_verbs = { alc680_init_verbs },
19154 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19155 .dac_nids = alc680_dac_nids,
19156 .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
19157 .adc_nids = alc680_adc_nids,
19158 .hp_nid = 0x04,
19159 .dig_out_nid = ALC680_DIGOUT_NID,
19160 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19161 .channel_mode = alc680_modes,
19162 .input_mux = &alc680_capture_source,
19163 },
19164};
19165
19166static int patch_alc680(struct hda_codec *codec)
19167{
19168 struct alc_spec *spec;
19169 int board_config;
19170 int err;
19171
19172 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19173 if (spec == NULL)
19174 return -ENOMEM;
19175
19176 codec->spec = spec;
19177
19178 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19179 alc680_models,
19180 alc680_cfg_tbl);
19181
19182 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19183 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19184 codec->chip_name);
19185 board_config = ALC680_AUTO;
19186 }
19187
19188 if (board_config == ALC680_AUTO) {
19189 /* automatic parse from the BIOS config */
19190 err = alc680_parse_auto_config(codec);
19191 if (err < 0) {
19192 alc_free(codec);
19193 return err;
19194 } else if (!err) {
19195 printk(KERN_INFO
19196 "hda_codec: Cannot set up configuration "
19197 "from BIOS. Using base mode...\n");
19198 board_config = ALC680_BASE;
19199 }
19200 }
19201
19202 if (board_config != ALC680_AUTO)
19203 setup_preset(codec, &alc680_presets[board_config]);
19204
19205 spec->stream_analog_playback = &alc680_pcm_analog_playback;
19206 spec->stream_analog_capture = &alc680_pcm_analog_capture;
19207 spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
19208 spec->stream_digital_playback = &alc680_pcm_digital_playback;
19209
19210 if (!spec->adc_nids) {
19211 spec->adc_nids = alc680_adc_nids;
19212 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19213 }
19214
19215 if (!spec->cap_mixer)
19216 set_capture_mixer(codec);
19217
19218 spec->vmaster_nid = 0x02;
19219
19220 codec->patch_ops = alc_patch_ops;
19221 if (board_config == ALC680_AUTO)
19222 spec->init_hook = alc680_auto_init;
19223
19224 return 0;
19225}
19226
19227/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019228 * patch entries
19229 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019230static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019231 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019232 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019233 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019234 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019235 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019236 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019237 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019238 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019239 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019240 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019241 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19242 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19243 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019244 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020019245 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019246 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19247 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019248 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019249 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019250 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019251 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019252 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019253 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019254 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019255 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019256 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019257 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019258 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019259 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019260 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019261 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020019262 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019263 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020019264 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019265 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019266 {} /* terminator */
19267};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019268
19269MODULE_ALIAS("snd-hda-codec-id:10ec*");
19270
19271MODULE_LICENSE("GPL");
19272MODULE_DESCRIPTION("Realtek HD-audio codec");
19273
19274static struct hda_codec_preset_list realtek_list = {
19275 .preset = snd_hda_preset_realtek,
19276 .owner = THIS_MODULE,
19277};
19278
19279static int __init patch_realtek_init(void)
19280{
19281 return snd_hda_add_codec_preset(&realtek_list);
19282}
19283
19284static void __exit patch_realtek_exit(void)
19285{
19286 snd_hda_delete_codec_preset(&realtek_list);
19287}
19288
19289module_init(patch_realtek_init)
19290module_exit(patch_realtek_exit)