blob: 4d3a6f05c703712c868f7671bd442687a7611d5f [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 Iwai954a29c2010-07-30 10:55:44 +0200850 unsigned int oldval;
851 oldval = snd_hda_codec_read(codec, nid, 0,
852 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100853 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100854 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200855 /* if the default pin setup is vref50, we give it priority */
856 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100857 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200858 else if (pincap & AC_PINCAP_VREF_50)
859 val = PIN_VREF50;
860 else if (pincap & AC_PINCAP_VREF_100)
861 val = PIN_VREF100;
862 else if (pincap & AC_PINCAP_VREF_GRD)
863 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100864 }
865 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
866}
867
868/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100869 */
870static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
871{
872 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
873 return;
874 spec->mixers[spec->num_mixers++] = mix;
875}
876
877static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
878{
879 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
880 return;
881 spec->init_verbs[spec->num_init_verbs++] = verb;
882}
883
884/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100885 * set up from the preset table
886 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200887static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200888 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100889{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200890 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100891 int i;
892
893 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100894 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100895 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200896 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
897 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100898 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200899
Kailang Yangdf694da2005-12-05 19:42:22 +0100900 spec->channel_mode = preset->channel_mode;
901 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200902 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200903 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100904
Hector Martin3b315d72009-06-02 10:54:19 +0200905 if (preset->const_channel_count)
906 spec->multiout.max_channels = preset->const_channel_count;
907 else
908 spec->multiout.max_channels = spec->channel_mode[0].channels;
909 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100910
911 spec->multiout.num_dacs = preset->num_dacs;
912 spec->multiout.dac_nids = preset->dac_nids;
913 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800914 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100915 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200916
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200917 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200918 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200919 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100920 spec->input_mux = preset->input_mux;
921
922 spec->num_adc_nids = preset->num_adc_nids;
923 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100924 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100925 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100926
927 spec->unsol_event = preset->unsol_event;
928 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200929#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100930 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200931 spec->loopback.amplist = preset->loopbacks;
932#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200933
934 if (preset->setup)
935 preset->setup(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100936}
937
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200938/* Enable GPIO mask and set output */
939static struct hda_verb alc_gpio1_init_verbs[] = {
940 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
941 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
942 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
943 { }
944};
945
946static struct hda_verb alc_gpio2_init_verbs[] = {
947 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
948 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
949 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
950 { }
951};
952
Kailang Yangbdd148a2007-05-08 15:19:08 +0200953static struct hda_verb alc_gpio3_init_verbs[] = {
954 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
955 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
956 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
957 { }
958};
959
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200960/*
961 * Fix hardware PLL issue
962 * On some codecs, the analog PLL gating control must be off while
963 * the default value is 1.
964 */
965static void alc_fix_pll(struct hda_codec *codec)
966{
967 struct alc_spec *spec = codec->spec;
968 unsigned int val;
969
970 if (!spec->pll_nid)
971 return;
972 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
973 spec->pll_coef_idx);
974 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
975 AC_VERB_GET_PROC_COEF, 0);
976 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
977 spec->pll_coef_idx);
978 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
979 val & ~(1 << spec->pll_coef_bit));
980}
981
982static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
983 unsigned int coef_idx, unsigned int coef_bit)
984{
985 struct alc_spec *spec = codec->spec;
986 spec->pll_nid = nid;
987 spec->pll_coef_idx = coef_idx;
988 spec->pll_coef_bit = coef_bit;
989 alc_fix_pll(codec);
990}
991
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200992static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200993{
994 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200995 unsigned int nid = spec->autocfg.hp_pins[0];
996 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200997
Takashi Iwaiad87c642009-11-02 14:23:15 +0100998 if (!nid)
999 return;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001000 spec->jack_present = snd_hda_jack_detect(codec, nid);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001001 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1002 nid = spec->autocfg.speaker_pins[i];
1003 if (!nid)
1004 break;
1005 snd_hda_codec_write(codec, nid, 0,
1006 AC_VERB_SET_PIN_WIDGET_CONTROL,
1007 spec->jack_present ? 0 : PIN_OUT);
1008 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001009}
1010
Takashi Iwai6c819492009-08-10 18:47:44 +02001011static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1012 hda_nid_t nid)
1013{
1014 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1015 int i, nums;
1016
1017 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1018 for (i = 0; i < nums; i++)
1019 if (conn[i] == nid)
1020 return i;
1021 return -1;
1022}
1023
Takashi Iwai840b64c2010-07-13 22:49:01 +02001024/* switch the current ADC according to the jack state */
1025static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1026{
1027 struct alc_spec *spec = codec->spec;
1028 unsigned int present;
1029 hda_nid_t new_adc;
1030
1031 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1032 if (present)
1033 spec->cur_adc_idx = 1;
1034 else
1035 spec->cur_adc_idx = 0;
1036 new_adc = spec->adc_nids[spec->cur_adc_idx];
1037 if (spec->cur_adc && spec->cur_adc != new_adc) {
1038 /* stream is running, let's swap the current ADC */
1039 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
1040 spec->cur_adc = new_adc;
1041 snd_hda_codec_setup_stream(codec, new_adc,
1042 spec->cur_adc_stream_tag, 0,
1043 spec->cur_adc_format);
1044 }
1045}
1046
Kailang Yang7fb0d782008-10-15 11:12:35 +02001047static void alc_mic_automute(struct hda_codec *codec)
1048{
1049 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001050 struct alc_mic_route *dead, *alive;
1051 unsigned int present, type;
1052 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001053
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001054 if (!spec->auto_mic)
1055 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001056 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1057 return;
1058 if (snd_BUG_ON(!spec->adc_nids))
1059 return;
1060
Takashi Iwai840b64c2010-07-13 22:49:01 +02001061 if (spec->dual_adc_switch) {
1062 alc_dual_mic_adc_auto_switch(codec);
1063 return;
1064 }
1065
Takashi Iwai6c819492009-08-10 18:47:44 +02001066 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1067
Wu Fengguang864f92b2009-11-18 12:38:02 +08001068 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001069 if (present) {
1070 alive = &spec->ext_mic;
1071 dead = &spec->int_mic;
1072 } else {
1073 alive = &spec->int_mic;
1074 dead = &spec->ext_mic;
1075 }
1076
Takashi Iwai6c819492009-08-10 18:47:44 +02001077 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1078 if (type == AC_WID_AUD_MIX) {
1079 /* Matrix-mixer style (e.g. ALC882) */
1080 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1081 alive->mux_idx,
1082 HDA_AMP_MUTE, 0);
1083 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1084 dead->mux_idx,
1085 HDA_AMP_MUTE, HDA_AMP_MUTE);
1086 } else {
1087 /* MUX style (e.g. ALC880) */
1088 snd_hda_codec_write_cache(codec, cap_nid, 0,
1089 AC_VERB_SET_CONNECT_SEL,
1090 alive->mux_idx);
1091 }
1092
1093 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001094}
1095
Kailang Yangc9b58002007-10-16 14:30:01 +02001096/* unsolicited event for HP jack sensing */
1097static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1098{
1099 if (codec->vendor_id == 0x10ec0880)
1100 res >>= 28;
1101 else
1102 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001103 switch (res) {
1104 case ALC880_HP_EVENT:
1105 alc_automute_pin(codec);
1106 break;
1107 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001108 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001109 break;
1110 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001111}
1112
1113static void alc_inithook(struct hda_codec *codec)
1114{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001115 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001116 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001117}
1118
Kailang Yangf9423e72008-05-27 12:32:25 +02001119/* additional initialization for ALC888 variants */
1120static void alc888_coef_init(struct hda_codec *codec)
1121{
1122 unsigned int tmp;
1123
1124 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1125 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1126 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001127 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001128 /* alc888S-VC */
1129 snd_hda_codec_read(codec, 0x20, 0,
1130 AC_VERB_SET_PROC_COEF, 0x830);
1131 else
1132 /* alc888-VB */
1133 snd_hda_codec_read(codec, 0x20, 0,
1134 AC_VERB_SET_PROC_COEF, 0x3030);
1135}
1136
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001137static void alc889_coef_init(struct hda_codec *codec)
1138{
1139 unsigned int tmp;
1140
1141 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1142 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1143 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1144 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1145}
1146
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001147/* turn on/off EAPD control (only if available) */
1148static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1149{
1150 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1151 return;
1152 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1153 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1154 on ? 2 : 0);
1155}
1156
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001157static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001158{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001159 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001160
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001161 switch (type) {
1162 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001163 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1164 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001165 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001166 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1167 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001168 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001169 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1170 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001171 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001172 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001173 case 0x10ec0260:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001174 set_eapd(codec, 0x0f, 1);
1175 set_eapd(codec, 0x10, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001176 break;
1177 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001178 case 0x10ec0267:
1179 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001180 case 0x10ec0269:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001181 case 0x10ec0270:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001182 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001183 case 0x10ec0660:
1184 case 0x10ec0662:
1185 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001186 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001187 case 0x10ec0889:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001188 set_eapd(codec, 0x14, 1);
1189 set_eapd(codec, 0x15, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001190 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001191 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001192 switch (codec->vendor_id) {
1193 case 0x10ec0260:
1194 snd_hda_codec_write(codec, 0x1a, 0,
1195 AC_VERB_SET_COEF_INDEX, 7);
1196 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1197 AC_VERB_GET_PROC_COEF, 0);
1198 snd_hda_codec_write(codec, 0x1a, 0,
1199 AC_VERB_SET_COEF_INDEX, 7);
1200 snd_hda_codec_write(codec, 0x1a, 0,
1201 AC_VERB_SET_PROC_COEF,
1202 tmp | 0x2010);
1203 break;
1204 case 0x10ec0262:
1205 case 0x10ec0880:
1206 case 0x10ec0882:
1207 case 0x10ec0883:
1208 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001209 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001210 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001211 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001212 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001213 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001214 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001215 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001216#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001217 case 0x10ec0267:
1218 case 0x10ec0268:
1219 snd_hda_codec_write(codec, 0x20, 0,
1220 AC_VERB_SET_COEF_INDEX, 7);
1221 tmp = snd_hda_codec_read(codec, 0x20, 0,
1222 AC_VERB_GET_PROC_COEF, 0);
1223 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001224 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001225 snd_hda_codec_write(codec, 0x20, 0,
1226 AC_VERB_SET_PROC_COEF,
1227 tmp | 0x3000);
1228 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001229#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001230 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001231 break;
1232 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001233}
Kailang Yangea1fb292008-08-26 12:58:38 +02001234
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001235static void alc_init_auto_hp(struct hda_codec *codec)
1236{
1237 struct alc_spec *spec = codec->spec;
1238
1239 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001240 return;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001241
Kailang Yangc9b58002007-10-16 14:30:01 +02001242 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001243 if (spec->autocfg.line_out_pins[0] &&
1244 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001245 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001246 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001247 else
1248 return;
1249 }
1250
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001251 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1252 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001253 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1254 AC_VERB_SET_UNSOLICITED_ENABLE,
1255 AC_USRSP_EN | ALC880_HP_EVENT);
1256 spec->unsol_event = alc_sku_unsol_event;
1257}
1258
Takashi Iwai6c819492009-08-10 18:47:44 +02001259static void alc_init_auto_mic(struct hda_codec *codec)
1260{
1261 struct alc_spec *spec = codec->spec;
1262 struct auto_pin_cfg *cfg = &spec->autocfg;
1263 hda_nid_t fixed, ext;
1264 int i;
1265
1266 /* there must be only two mic inputs exclusively */
1267 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
1268 if (cfg->input_pins[i])
1269 return;
1270
1271 fixed = ext = 0;
1272 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
1273 hda_nid_t nid = cfg->input_pins[i];
1274 unsigned int defcfg;
1275 if (!nid)
1276 return;
1277 defcfg = snd_hda_codec_get_pincfg(codec, nid);
1278 switch (get_defcfg_connect(defcfg)) {
1279 case AC_JACK_PORT_FIXED:
1280 if (fixed)
1281 return; /* already occupied */
1282 fixed = nid;
1283 break;
1284 case AC_JACK_PORT_COMPLEX:
1285 if (ext)
1286 return; /* already occupied */
1287 ext = nid;
1288 break;
1289 default:
1290 return; /* invalid entry */
1291 }
1292 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001293 if (!ext || !fixed)
1294 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001295 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1296 return; /* no unsol support */
1297 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1298 ext, fixed);
1299 spec->ext_mic.pin = ext;
1300 spec->int_mic.pin = fixed;
1301 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1302 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1303 spec->auto_mic = 1;
1304 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1305 AC_VERB_SET_UNSOLICITED_ENABLE,
1306 AC_USRSP_EN | ALC880_MIC_EVENT);
1307 spec->unsol_event = alc_sku_unsol_event;
1308}
1309
Kailang Yangda00c242010-03-19 11:23:45 +01001310static int alc_auto_parse_customize_define(struct hda_codec *codec)
1311{
1312 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001313 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001314 struct alc_spec *spec = codec->spec;
1315
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001316 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1317
Kailang Yangda00c242010-03-19 11:23:45 +01001318 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001319 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001320 goto do_sku;
1321
1322 nid = 0x1d;
1323 if (codec->vendor_id == 0x10ec0260)
1324 nid = 0x17;
1325 ass = snd_hda_codec_get_pincfg(codec, nid);
1326
1327 if (!(ass & 1)) {
1328 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1329 codec->chip_name, ass);
1330 return -1;
1331 }
1332
1333 /* check sum */
1334 tmp = 0;
1335 for (i = 1; i < 16; i++) {
1336 if ((ass >> i) & 1)
1337 tmp++;
1338 }
1339 if (((ass >> 16) & 0xf) != tmp)
1340 return -1;
1341
1342 spec->cdefine.port_connectivity = ass >> 30;
1343 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1344 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1345 spec->cdefine.customization = ass >> 8;
1346do_sku:
1347 spec->cdefine.sku_cfg = ass;
1348 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1349 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1350 spec->cdefine.swap = (ass & 0x2) >> 1;
1351 spec->cdefine.override = ass & 0x1;
1352
1353 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1354 nid, spec->cdefine.sku_cfg);
1355 snd_printd("SKU: port_connectivity=0x%x\n",
1356 spec->cdefine.port_connectivity);
1357 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1358 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1359 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1360 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1361 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1362 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1363 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1364
1365 return 0;
1366}
1367
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001368/* check subsystem ID and set up device-specific initialization;
1369 * return 1 if initialized, 0 if invalid SSID
1370 */
1371/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1372 * 31 ~ 16 : Manufacture ID
1373 * 15 ~ 8 : SKU ID
1374 * 7 ~ 0 : Assembly ID
1375 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1376 */
1377static int alc_subsystem_id(struct hda_codec *codec,
1378 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001379 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001380{
1381 unsigned int ass, tmp, i;
1382 unsigned nid;
1383 struct alc_spec *spec = codec->spec;
1384
1385 ass = codec->subsystem_id & 0xffff;
1386 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1387 goto do_sku;
1388
1389 /* invalid SSID, check the special NID pin defcfg instead */
1390 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001391 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001392 * 29~21 : reserve
1393 * 20 : PCBEEP input
1394 * 19~16 : Check sum (15:1)
1395 * 15~1 : Custom
1396 * 0 : override
1397 */
1398 nid = 0x1d;
1399 if (codec->vendor_id == 0x10ec0260)
1400 nid = 0x17;
1401 ass = snd_hda_codec_get_pincfg(codec, nid);
1402 snd_printd("realtek: No valid SSID, "
1403 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001404 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001405 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001406 return 0;
1407 if ((ass >> 30) != 1) /* no physical connection */
1408 return 0;
1409
1410 /* check sum */
1411 tmp = 0;
1412 for (i = 1; i < 16; i++) {
1413 if ((ass >> i) & 1)
1414 tmp++;
1415 }
1416 if (((ass >> 16) & 0xf) != tmp)
1417 return 0;
1418do_sku:
1419 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1420 ass & 0xffff, codec->vendor_id);
1421 /*
1422 * 0 : override
1423 * 1 : Swap Jack
1424 * 2 : 0 --> Desktop, 1 --> Laptop
1425 * 3~5 : External Amplifier control
1426 * 7~6 : Reserved
1427 */
1428 tmp = (ass & 0x38) >> 3; /* external Amp control */
1429 switch (tmp) {
1430 case 1:
1431 spec->init_amp = ALC_INIT_GPIO1;
1432 break;
1433 case 3:
1434 spec->init_amp = ALC_INIT_GPIO2;
1435 break;
1436 case 7:
1437 spec->init_amp = ALC_INIT_GPIO3;
1438 break;
1439 case 5:
1440 spec->init_amp = ALC_INIT_DEFAULT;
1441 break;
1442 }
1443
1444 /* is laptop or Desktop and enable the function "Mute internal speaker
1445 * when the external headphone out jack is plugged"
1446 */
1447 if (!(ass & 0x8000))
1448 return 1;
1449 /*
1450 * 10~8 : Jack location
1451 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1452 * 14~13: Resvered
1453 * 15 : 1 --> enable the function "Mute internal speaker
1454 * when the external headphone out jack is plugged"
1455 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001456 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001457 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001458 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1459 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001460 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001461 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001462 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001463 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001464 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001465 else if (tmp == 3)
1466 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001467 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001468 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001469 for (i = 0; i < spec->autocfg.line_outs; i++)
1470 if (spec->autocfg.line_out_pins[i] == nid)
1471 return 1;
1472 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001473 }
1474
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001475 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001476 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001477 return 1;
1478}
Kailang Yangea1fb292008-08-26 12:58:38 +02001479
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001480static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001481 hda_nid_t porta, hda_nid_t porte,
1482 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001483{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001484 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001485 struct alc_spec *spec = codec->spec;
1486 snd_printd("realtek: "
1487 "Enable default setup for auto mode as fallback\n");
1488 spec->init_amp = ALC_INIT_DEFAULT;
1489 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001490 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001491 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001492}
1493
Takashi Iwai41e41f12005-06-08 14:48:49 +02001494/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001495 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001496 */
1497
1498struct alc_pincfg {
1499 hda_nid_t nid;
1500 u32 val;
1501};
1502
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001503struct alc_fixup {
1504 const struct alc_pincfg *pins;
1505 const struct hda_verb *verbs;
1506};
1507
1508static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaif95474e2007-07-10 00:47:43 +02001509 const struct snd_pci_quirk *quirk,
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001510 const struct alc_fixup *fix,
1511 int pre_init)
Takashi Iwaif95474e2007-07-10 00:47:43 +02001512{
1513 const struct alc_pincfg *cfg;
1514
1515 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1516 if (!quirk)
1517 return;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001518 fix += quirk->value;
1519 cfg = fix->pins;
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001520 if (pre_init && cfg) {
1521#ifdef CONFIG_SND_DEBUG_VERBOSE
1522 snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
1523 codec->chip_name, quirk->name);
1524#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001525 for (; cfg->nid; cfg++)
1526 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
1527 }
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001528 if (!pre_init && fix->verbs) {
1529#ifdef CONFIG_SND_DEBUG_VERBOSE
1530 snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
1531 codec->chip_name, quirk->name);
1532#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001533 add_verb(codec->spec, fix->verbs);
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001534 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001535}
1536
Kailang Yang274693f2009-12-03 10:07:50 +01001537static int alc_read_coef_idx(struct hda_codec *codec,
1538 unsigned int coef_idx)
1539{
1540 unsigned int val;
1541 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1542 coef_idx);
1543 val = snd_hda_codec_read(codec, 0x20, 0,
1544 AC_VERB_GET_PROC_COEF, 0);
1545 return val;
1546}
1547
Takashi Iwai757899a2010-07-30 10:48:14 +02001548/* set right pin controls for digital I/O */
1549static void alc_auto_init_digital(struct hda_codec *codec)
1550{
1551 struct alc_spec *spec = codec->spec;
1552 int i;
1553 hda_nid_t pin;
1554
1555 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1556 pin = spec->autocfg.dig_out_pins[i];
1557 if (pin) {
1558 snd_hda_codec_write(codec, pin, 0,
1559 AC_VERB_SET_PIN_WIDGET_CONTROL,
1560 PIN_OUT);
1561 }
1562 }
1563 pin = spec->autocfg.dig_in_pin;
1564 if (pin)
1565 snd_hda_codec_write(codec, pin, 0,
1566 AC_VERB_SET_PIN_WIDGET_CONTROL,
1567 PIN_IN);
1568}
1569
1570/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1571static void alc_auto_parse_digital(struct hda_codec *codec)
1572{
1573 struct alc_spec *spec = codec->spec;
1574 int i, err;
1575 hda_nid_t dig_nid;
1576
1577 /* support multiple SPDIFs; the secondary is set up as a slave */
1578 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1579 err = snd_hda_get_connections(codec,
1580 spec->autocfg.dig_out_pins[i],
1581 &dig_nid, 1);
1582 if (err < 0)
1583 continue;
1584 if (!i) {
1585 spec->multiout.dig_out_nid = dig_nid;
1586 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1587 } else {
1588 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
1589 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
1590 break;
1591 spec->slave_dig_outs[i - 1] = dig_nid;
1592 }
1593 }
1594
1595 if (spec->autocfg.dig_in_pin) {
1596 hda_nid_t dig_nid;
1597 err = snd_hda_get_connections(codec,
1598 spec->autocfg.dig_in_pin,
1599 &dig_nid, 1);
1600 if (err > 0)
1601 spec->dig_in_nid = dig_nid;
1602 }
1603}
1604
Takashi Iwaif95474e2007-07-10 00:47:43 +02001605/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001606 * ALC888
1607 */
1608
1609/*
1610 * 2ch mode
1611 */
1612static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1613/* Mic-in jack as mic in */
1614 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1615 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1616/* Line-in jack as Line in */
1617 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1618 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1619/* Line-Out as Front */
1620 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1621 { } /* end */
1622};
1623
1624/*
1625 * 4ch mode
1626 */
1627static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1628/* Mic-in jack as mic in */
1629 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1630 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1631/* Line-in jack as Surround */
1632 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1633 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1634/* Line-Out as Front */
1635 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1636 { } /* end */
1637};
1638
1639/*
1640 * 6ch mode
1641 */
1642static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1643/* Mic-in jack as CLFE */
1644 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1645 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1646/* Line-in jack as Surround */
1647 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1648 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1649/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1650 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1651 { } /* end */
1652};
1653
1654/*
1655 * 8ch mode
1656 */
1657static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1658/* Mic-in jack as CLFE */
1659 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1660 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1661/* Line-in jack as Surround */
1662 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1663 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1664/* Line-Out as Side */
1665 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1666 { } /* end */
1667};
1668
1669static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1670 { 2, alc888_4ST_ch2_intel_init },
1671 { 4, alc888_4ST_ch4_intel_init },
1672 { 6, alc888_4ST_ch6_intel_init },
1673 { 8, alc888_4ST_ch8_intel_init },
1674};
1675
1676/*
1677 * ALC888 Fujitsu Siemens Amillo xa3530
1678 */
1679
1680static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1681/* Front Mic: set to PIN_IN (empty by default) */
1682 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1683/* Connect Internal HP to Front */
1684 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1685 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1686 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1687/* Connect Bass HP to Front */
1688 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1689 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1690 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1691/* Connect Line-Out side jack (SPDIF) to Side */
1692 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1693 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1694 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1695/* Connect Mic jack to CLFE */
1696 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1697 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1698 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1699/* Connect Line-in jack to Surround */
1700 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1701 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1702 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1703/* Connect HP out jack to Front */
1704 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1705 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1706 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1707/* Enable unsolicited event for HP jack and Line-out jack */
1708 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1709 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1710 {}
1711};
1712
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001713static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001714{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001715 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001716 unsigned int mute;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001717 hda_nid_t nid;
1718 int i;
1719
1720 spec->jack_present = 0;
1721 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1722 nid = spec->autocfg.hp_pins[i];
1723 if (!nid)
1724 break;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001725 if (snd_hda_jack_detect(codec, nid)) {
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001726 spec->jack_present = 1;
1727 break;
1728 }
1729 }
1730
1731 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001732 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001733 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1734 nid = spec->autocfg.speaker_pins[i];
1735 if (!nid)
1736 break;
1737 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1738 HDA_AMP_MUTE, mute);
1739 }
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001740}
1741
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001742static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1743 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001744{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001745 if (codec->vendor_id == 0x10ec0880)
1746 res >>= 28;
1747 else
1748 res >>= 26;
1749 if (res == ALC880_HP_EVENT)
1750 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001751}
1752
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001753static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001754{
1755 struct alc_spec *spec = codec->spec;
1756
1757 spec->autocfg.hp_pins[0] = 0x15;
1758 spec->autocfg.speaker_pins[0] = 0x14;
1759 spec->autocfg.speaker_pins[1] = 0x16;
1760 spec->autocfg.speaker_pins[2] = 0x17;
1761 spec->autocfg.speaker_pins[3] = 0x19;
1762 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001763}
1764
1765static void alc889_intel_init_hook(struct hda_codec *codec)
1766{
1767 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001768 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001769}
1770
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001771static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001772{
1773 struct alc_spec *spec = codec->spec;
1774
1775 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1776 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1777 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1778 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001779}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001780
1781/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001782 * ALC888 Acer Aspire 4930G model
1783 */
1784
1785static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1786/* Front Mic: set to PIN_IN (empty by default) */
1787 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1788/* Unselect Front Mic by default in input mixer 3 */
1789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001790/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001791 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1792/* Connect Internal HP to front */
1793 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1794 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1795 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1796/* Connect HP out to front */
1797 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1798 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1799 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1800 { }
1801};
1802
Hector Martin3b315d72009-06-02 10:54:19 +02001803/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01001804 * ALC888 Acer Aspire 6530G model
1805 */
1806
1807static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01001808/* Route to built-in subwoofer as well as speakers */
1809 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1810 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1811 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1812 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001813/* Bias voltage on for external mic port */
1814 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02001815/* Front Mic: set to PIN_IN (empty by default) */
1816 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1817/* Unselect Front Mic by default in input mixer 3 */
1818 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001819/* Enable unsolicited event for HP jack */
1820 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1821/* Enable speaker output */
1822 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1823 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01001824 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001825/* Enable headphone output */
1826 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
1827 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1828 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01001829 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001830 { }
1831};
1832
1833/*
Hector Martin018df412009-06-04 00:13:40 +02001834 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001835 */
1836
Hector Martin018df412009-06-04 00:13:40 +02001837static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001838/* Front Mic: set to PIN_IN (empty by default) */
1839 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1840/* Unselect Front Mic by default in input mixer 3 */
1841 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1842/* Enable unsolicited event for HP jack */
1843 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1844/* Connect Internal Front to Front */
1845 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1846 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1847 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1848/* Connect Internal Rear to Rear */
1849 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1850 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1851 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1852/* Connect Internal CLFE to CLFE */
1853 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1854 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1855 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1856/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02001857 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02001858 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1859 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1860/* Enable all DACs */
1861/* DAC DISABLE/MUTE 1? */
1862/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
1863 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
1864 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1865/* DAC DISABLE/MUTE 2? */
1866/* some bit here disables the other DACs. Init=0x4900 */
1867 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
1868 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02001869/* DMIC fix
1870 * This laptop has a stereo digital microphone. The mics are only 1cm apart
1871 * which makes the stereo useless. However, either the mic or the ALC889
1872 * makes the signal become a difference/sum signal instead of standard
1873 * stereo, which is annoying. So instead we flip this bit which makes the
1874 * codec replicate the sum signal to both channels, turning it into a
1875 * normal mono mic.
1876 */
1877/* DMIC_CONTROL? Init value = 0x0001 */
1878 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
1879 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02001880 { }
1881};
1882
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001883static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001884 /* Front mic only available on one ADC */
1885 {
1886 .num_items = 4,
1887 .items = {
1888 { "Mic", 0x0 },
1889 { "Line", 0x2 },
1890 { "CD", 0x4 },
1891 { "Front Mic", 0xb },
1892 },
1893 },
1894 {
1895 .num_items = 3,
1896 .items = {
1897 { "Mic", 0x0 },
1898 { "Line", 0x2 },
1899 { "CD", 0x4 },
1900 },
1901 }
1902};
1903
Tony Vroond2fd4b02009-06-21 00:40:10 +01001904static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
1905 /* Interal mic only available on one ADC */
1906 {
Tony Vroon684a8842009-06-26 09:27:50 +01001907 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001908 .items = {
1909 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001910 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001911 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001912 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001913 { "Int Mic", 0xb },
1914 },
1915 },
1916 {
Tony Vroon684a8842009-06-26 09:27:50 +01001917 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001918 .items = {
1919 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001920 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001921 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001922 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001923 },
1924 }
1925};
1926
Hector Martin018df412009-06-04 00:13:40 +02001927static struct hda_input_mux alc889_capture_sources[3] = {
1928 /* Digital mic only available on first "ADC" */
1929 {
1930 .num_items = 5,
1931 .items = {
1932 { "Mic", 0x0 },
1933 { "Line", 0x2 },
1934 { "CD", 0x4 },
1935 { "Front Mic", 0xb },
1936 { "Input Mix", 0xa },
1937 },
1938 },
1939 {
1940 .num_items = 4,
1941 .items = {
1942 { "Mic", 0x0 },
1943 { "Line", 0x2 },
1944 { "CD", 0x4 },
1945 { "Input Mix", 0xa },
1946 },
1947 },
1948 {
1949 .num_items = 4,
1950 .items = {
1951 { "Mic", 0x0 },
1952 { "Line", 0x2 },
1953 { "CD", 0x4 },
1954 { "Input Mix", 0xa },
1955 },
1956 }
1957};
1958
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001959static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001960 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1961 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1962 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1963 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1964 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1965 HDA_OUTPUT),
1966 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1967 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1968 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1969 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1970 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1971 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1972 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1973 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1974 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1975 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1976 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1977 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001978 { } /* end */
1979};
1980
Hector Martin556eea92009-12-20 22:51:23 +01001981static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
1982 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1983 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1984 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1985 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1986 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1987 HDA_OUTPUT),
1988 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1989 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1990 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1991 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1992 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1993 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1994 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1995 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1996 { } /* end */
1997};
1998
1999
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002000static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002001{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002002 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002003
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002004 spec->autocfg.hp_pins[0] = 0x15;
2005 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002006 spec->autocfg.speaker_pins[1] = 0x16;
2007 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002008}
2009
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002010static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002011{
2012 struct alc_spec *spec = codec->spec;
2013
2014 spec->autocfg.hp_pins[0] = 0x15;
2015 spec->autocfg.speaker_pins[0] = 0x14;
2016 spec->autocfg.speaker_pins[1] = 0x16;
2017 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02002018}
2019
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002020static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002021{
2022 struct alc_spec *spec = codec->spec;
2023
2024 spec->autocfg.hp_pins[0] = 0x15;
2025 spec->autocfg.speaker_pins[0] = 0x14;
2026 spec->autocfg.speaker_pins[1] = 0x16;
2027 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02002028}
2029
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002030/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002031 * ALC880 3-stack model
2032 *
2033 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002034 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2035 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 */
2037
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002038static hda_nid_t alc880_dac_nids[4] = {
2039 /* front, rear, clfe, rear_surr */
2040 0x02, 0x05, 0x04, 0x03
2041};
2042
2043static hda_nid_t alc880_adc_nids[3] = {
2044 /* ADC0-2 */
2045 0x07, 0x08, 0x09,
2046};
2047
2048/* The datasheet says the node 0x07 is connected from inputs,
2049 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002050 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002052static hda_nid_t alc880_adc_nids_alt[2] = {
2053 /* ADC1-2 */
2054 0x08, 0x09,
2055};
2056
2057#define ALC880_DIGOUT_NID 0x06
2058#define ALC880_DIGIN_NID 0x0a
2059
2060static struct hda_input_mux alc880_capture_source = {
2061 .num_items = 4,
2062 .items = {
2063 { "Mic", 0x0 },
2064 { "Front Mic", 0x3 },
2065 { "Line", 0x2 },
2066 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002068};
2069
2070/* channel source setting (2/6 channel selection for 3-stack) */
2071/* 2ch mode */
2072static struct hda_verb alc880_threestack_ch2_init[] = {
2073 /* set line-in to input, mute it */
2074 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2075 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2076 /* set mic-in to input vref 80%, mute it */
2077 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2078 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 { } /* end */
2080};
2081
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002082/* 6ch mode */
2083static struct hda_verb alc880_threestack_ch6_init[] = {
2084 /* set line-in to output, unmute it */
2085 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2086 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2087 /* set mic-in to output, unmute it */
2088 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2089 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2090 { } /* end */
2091};
2092
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002093static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002094 { 2, alc880_threestack_ch2_init },
2095 { 6, alc880_threestack_ch6_init },
2096};
2097
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002098static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002099 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002100 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002101 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002102 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002103 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2104 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002105 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2106 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2108 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2109 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2110 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2111 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2112 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2113 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2114 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002116 {
2117 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2118 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002119 .info = alc_ch_mode_info,
2120 .get = alc_ch_mode_get,
2121 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002122 },
2123 { } /* end */
2124};
2125
2126/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002127static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2128 struct snd_ctl_elem_info *uinfo)
2129{
2130 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2131 struct alc_spec *spec = codec->spec;
2132 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002133
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002134 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002135 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2136 HDA_INPUT);
2137 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002138 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002139 return err;
2140}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002142static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2143 unsigned int size, unsigned int __user *tlv)
2144{
2145 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2146 struct alc_spec *spec = codec->spec;
2147 int err;
2148
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002149 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002150 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2151 HDA_INPUT);
2152 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002153 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002154 return err;
2155}
2156
2157typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2158 struct snd_ctl_elem_value *ucontrol);
2159
2160static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2161 struct snd_ctl_elem_value *ucontrol,
2162 getput_call_t func)
2163{
2164 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2165 struct alc_spec *spec = codec->spec;
2166 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2167 int err;
2168
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002169 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002170 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2171 3, 0, HDA_INPUT);
2172 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002173 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002174 return err;
2175}
2176
2177static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2178 struct snd_ctl_elem_value *ucontrol)
2179{
2180 return alc_cap_getput_caller(kcontrol, ucontrol,
2181 snd_hda_mixer_amp_volume_get);
2182}
2183
2184static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2185 struct snd_ctl_elem_value *ucontrol)
2186{
2187 return alc_cap_getput_caller(kcontrol, ucontrol,
2188 snd_hda_mixer_amp_volume_put);
2189}
2190
2191/* capture mixer elements */
2192#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2193
2194static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2195 struct snd_ctl_elem_value *ucontrol)
2196{
2197 return alc_cap_getput_caller(kcontrol, ucontrol,
2198 snd_hda_mixer_amp_switch_get);
2199}
2200
2201static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2202 struct snd_ctl_elem_value *ucontrol)
2203{
2204 return alc_cap_getput_caller(kcontrol, ucontrol,
2205 snd_hda_mixer_amp_switch_put);
2206}
2207
Takashi Iwaia23b6882009-03-23 15:21:36 +01002208#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002209 { \
2210 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2211 .name = "Capture Switch", \
2212 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2213 .count = num, \
2214 .info = alc_cap_sw_info, \
2215 .get = alc_cap_sw_get, \
2216 .put = alc_cap_sw_put, \
2217 }, \
2218 { \
2219 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2220 .name = "Capture Volume", \
2221 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2222 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2223 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2224 .count = num, \
2225 .info = alc_cap_vol_info, \
2226 .get = alc_cap_vol_get, \
2227 .put = alc_cap_vol_put, \
2228 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002229 }
2230
2231#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002232 { \
2233 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2234 /* .name = "Capture Source", */ \
2235 .name = "Input Source", \
2236 .count = num, \
2237 .info = alc_mux_enum_info, \
2238 .get = alc_mux_enum_get, \
2239 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002240 }
2241
2242#define DEFINE_CAPMIX(num) \
2243static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2244 _DEFINE_CAPMIX(num), \
2245 _DEFINE_CAPSRC(num), \
2246 { } /* end */ \
2247}
2248
2249#define DEFINE_CAPMIX_NOSRC(num) \
2250static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2251 _DEFINE_CAPMIX(num), \
2252 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002253}
2254
2255/* up to three ADCs */
2256DEFINE_CAPMIX(1);
2257DEFINE_CAPMIX(2);
2258DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002259DEFINE_CAPMIX_NOSRC(1);
2260DEFINE_CAPMIX_NOSRC(2);
2261DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002262
2263/*
2264 * ALC880 5-stack model
2265 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002266 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2267 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002268 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2269 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2270 */
2271
2272/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002273static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002274 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002275 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 { } /* end */
2277};
2278
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002279/* channel source setting (6/8 channel selection for 5-stack) */
2280/* 6ch mode */
2281static struct hda_verb alc880_fivestack_ch6_init[] = {
2282 /* set line-in to input, mute it */
2283 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2284 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002285 { } /* end */
2286};
2287
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002288/* 8ch mode */
2289static struct hda_verb alc880_fivestack_ch8_init[] = {
2290 /* set line-in to output, unmute it */
2291 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2292 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2293 { } /* end */
2294};
2295
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002296static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002297 { 6, alc880_fivestack_ch6_init },
2298 { 8, alc880_fivestack_ch8_init },
2299};
2300
2301
2302/*
2303 * ALC880 6-stack model
2304 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002305 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2306 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002307 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2308 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2309 */
2310
2311static hda_nid_t alc880_6st_dac_nids[4] = {
2312 /* front, rear, clfe, rear_surr */
2313 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002314};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002315
2316static struct hda_input_mux alc880_6stack_capture_source = {
2317 .num_items = 4,
2318 .items = {
2319 { "Mic", 0x0 },
2320 { "Front Mic", 0x1 },
2321 { "Line", 0x2 },
2322 { "CD", 0x4 },
2323 },
2324};
2325
2326/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002327static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002328 { 8, NULL },
2329};
2330
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002331static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002332 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002333 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002334 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002335 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002336 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2337 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002338 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2339 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002340 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002341 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002342 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2343 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2344 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2345 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2346 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2347 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2348 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2349 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002350 {
2351 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2352 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002353 .info = alc_ch_mode_info,
2354 .get = alc_ch_mode_get,
2355 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002356 },
2357 { } /* end */
2358};
2359
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002360
2361/*
2362 * ALC880 W810 model
2363 *
2364 * W810 has rear IO for:
2365 * Front (DAC 02)
2366 * Surround (DAC 03)
2367 * Center/LFE (DAC 04)
2368 * Digital out (06)
2369 *
2370 * The system also has a pair of internal speakers, and a headphone jack.
2371 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002372 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002373 * There is a variable resistor to control the speaker or headphone
2374 * volume. This is a hardware-only device without a software API.
2375 *
2376 * Plugging headphones in will disable the internal speakers. This is
2377 * implemented in hardware, not via the driver using jack sense. In
2378 * a similar fashion, plugging into the rear socket marked "front" will
2379 * disable both the speakers and headphones.
2380 *
2381 * For input, there's a microphone jack, and an "audio in" jack.
2382 * These may not do anything useful with this driver yet, because I
2383 * haven't setup any initialization verbs for these yet...
2384 */
2385
2386static hda_nid_t alc880_w810_dac_nids[3] = {
2387 /* front, rear/surround, clfe */
2388 0x02, 0x03, 0x04
2389};
2390
2391/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002392static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002393 { 6, NULL }
2394};
2395
2396/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002397static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002398 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002399 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002400 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002401 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002402 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2403 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002404 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2405 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002406 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2407 { } /* end */
2408};
2409
2410
2411/*
2412 * Z710V model
2413 *
2414 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002415 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2416 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002417 */
2418
2419static hda_nid_t alc880_z71v_dac_nids[1] = {
2420 0x02
2421};
2422#define ALC880_Z71V_HP_DAC 0x03
2423
2424/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002425static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002426 { 2, NULL }
2427};
2428
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002429static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002430 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002431 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002432 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002433 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +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("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2437 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2438 { } /* end */
2439};
2440
2441
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002442/*
2443 * ALC880 F1734 model
2444 *
2445 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2446 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2447 */
2448
2449static hda_nid_t alc880_f1734_dac_nids[1] = {
2450 0x03
2451};
2452#define ALC880_F1734_HP_DAC 0x02
2453
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002454static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002455 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002456 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002457 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2458 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002459 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2460 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002461 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2462 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002463 { } /* end */
2464};
2465
Takashi Iwai937b4162008-02-11 14:52:36 +01002466static struct hda_input_mux alc880_f1734_capture_source = {
2467 .num_items = 2,
2468 .items = {
2469 { "Mic", 0x1 },
2470 { "CD", 0x4 },
2471 },
2472};
2473
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002474
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002475/*
2476 * ALC880 ASUS model
2477 *
2478 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2479 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2480 * Mic = 0x18, Line = 0x1a
2481 */
2482
2483#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2484#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2485
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002486static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002487 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002488 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002489 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002490 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002491 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2492 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002493 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2494 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002495 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2496 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2497 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2498 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2499 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2500 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002501 {
2502 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2503 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002504 .info = alc_ch_mode_info,
2505 .get = alc_ch_mode_get,
2506 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002507 },
2508 { } /* end */
2509};
2510
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002511/*
2512 * ALC880 ASUS W1V model
2513 *
2514 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2515 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2516 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2517 */
2518
2519/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002520static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002521 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2522 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002523 { } /* end */
2524};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002525
Kailang Yangdf694da2005-12-05 19:42:22 +01002526/* TCL S700 */
2527static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2528 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2529 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2530 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2531 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2532 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2533 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2534 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2535 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2536 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002537 { } /* end */
2538};
2539
Kailang Yangccc656c2006-10-17 12:32:26 +02002540/* Uniwill */
2541static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002542 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2543 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2544 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2545 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002546 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2547 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2548 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2549 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2550 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2551 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2552 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2553 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2554 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2555 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2556 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2557 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002558 {
2559 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2560 .name = "Channel Mode",
2561 .info = alc_ch_mode_info,
2562 .get = alc_ch_mode_get,
2563 .put = alc_ch_mode_put,
2564 },
2565 { } /* end */
2566};
2567
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002568static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2569 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2570 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2571 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2572 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2573 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2574 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2575 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2576 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2577 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2578 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2579 { } /* end */
2580};
2581
Kailang Yangccc656c2006-10-17 12:32:26 +02002582static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002583 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2584 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2585 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2586 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002587 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2588 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2589 { } /* end */
2590};
2591
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002593 * virtual master controls
2594 */
2595
2596/*
2597 * slave controls for virtual master
2598 */
2599static const char *alc_slave_vols[] = {
2600 "Front Playback Volume",
2601 "Surround Playback Volume",
2602 "Center Playback Volume",
2603 "LFE Playback Volume",
2604 "Side Playback Volume",
2605 "Headphone Playback Volume",
2606 "Speaker Playback Volume",
2607 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002608 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002609 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002610 NULL,
2611};
2612
2613static const char *alc_slave_sws[] = {
2614 "Front Playback Switch",
2615 "Surround Playback Switch",
2616 "Center Playback Switch",
2617 "LFE Playback Switch",
2618 "Side Playback Switch",
2619 "Headphone Playback Switch",
2620 "Speaker Playback Switch",
2621 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002622 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002623 "Line-Out Playback Switch",
2624 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002625 NULL,
2626};
2627
2628/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002629 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002631
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002632#define NID_MAPPING (-1)
2633
2634#define SUBDEV_SPEAKER_ (0 << 6)
2635#define SUBDEV_HP_ (1 << 6)
2636#define SUBDEV_LINE_ (2 << 6)
2637#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2638#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2639#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2640
Takashi Iwai603c4012008-07-30 15:01:44 +02002641static void alc_free_kctls(struct hda_codec *codec);
2642
Takashi Iwai67d634c2009-11-16 15:35:59 +01002643#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002644/* additional beep mixers; the actual parameters are overwritten at build */
2645static struct snd_kcontrol_new alc_beep_mixer[] = {
2646 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002647 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002648 { } /* end */
2649};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002650#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652static int alc_build_controls(struct hda_codec *codec)
2653{
2654 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002655 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002656 struct snd_kcontrol_new *knew;
2657 int i, j, err;
2658 unsigned int u;
2659 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
2661 for (i = 0; i < spec->num_mixers; i++) {
2662 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2663 if (err < 0)
2664 return err;
2665 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002666 if (spec->cap_mixer) {
2667 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2668 if (err < 0)
2669 return err;
2670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002672 err = snd_hda_create_spdif_out_ctls(codec,
2673 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 if (err < 0)
2675 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002676 if (!spec->no_analog) {
2677 err = snd_hda_create_spdif_share_sw(codec,
2678 &spec->multiout);
2679 if (err < 0)
2680 return err;
2681 spec->multiout.share_spdif = 1;
2682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
2684 if (spec->dig_in_nid) {
2685 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2686 if (err < 0)
2687 return err;
2688 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002689
Takashi Iwai67d634c2009-11-16 15:35:59 +01002690#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002691 /* create beep controls if needed */
2692 if (spec->beep_amp) {
2693 struct snd_kcontrol_new *knew;
2694 for (knew = alc_beep_mixer; knew->name; knew++) {
2695 struct snd_kcontrol *kctl;
2696 kctl = snd_ctl_new1(knew, codec);
2697 if (!kctl)
2698 return -ENOMEM;
2699 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002700 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002701 if (err < 0)
2702 return err;
2703 }
2704 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002705#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002706
Takashi Iwai2134ea42008-01-10 16:53:55 +01002707 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002708 if (!spec->no_analog &&
2709 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002710 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002711 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002712 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002713 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002714 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002715 if (err < 0)
2716 return err;
2717 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002718 if (!spec->no_analog &&
2719 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002720 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2721 NULL, alc_slave_sws);
2722 if (err < 0)
2723 return err;
2724 }
2725
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002726 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02002727 if (spec->capsrc_nids || spec->adc_nids) {
2728 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2729 if (!kctl)
2730 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2731 for (i = 0; kctl && i < kctl->count; i++) {
2732 hda_nid_t *nids = spec->capsrc_nids;
2733 if (!nids)
2734 nids = spec->adc_nids;
2735 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
2736 if (err < 0)
2737 return err;
2738 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002739 }
2740 if (spec->cap_mixer) {
2741 const char *kname = kctl ? kctl->id.name : NULL;
2742 for (knew = spec->cap_mixer; knew->name; knew++) {
2743 if (kname && strcmp(knew->name, kname) == 0)
2744 continue;
2745 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2746 for (i = 0; kctl && i < kctl->count; i++) {
2747 err = snd_hda_add_nid(codec, kctl, i,
2748 spec->adc_nids[i]);
2749 if (err < 0)
2750 return err;
2751 }
2752 }
2753 }
2754
2755 /* other nid->control mapping */
2756 for (i = 0; i < spec->num_mixers; i++) {
2757 for (knew = spec->mixers[i]; knew->name; knew++) {
2758 if (knew->iface != NID_MAPPING)
2759 continue;
2760 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2761 if (kctl == NULL)
2762 continue;
2763 u = knew->subdevice;
2764 for (j = 0; j < 4; j++, u >>= 8) {
2765 nid = u & 0x3f;
2766 if (nid == 0)
2767 continue;
2768 switch (u & 0xc0) {
2769 case SUBDEV_SPEAKER_:
2770 nid = spec->autocfg.speaker_pins[nid];
2771 break;
2772 case SUBDEV_LINE_:
2773 nid = spec->autocfg.line_out_pins[nid];
2774 break;
2775 case SUBDEV_HP_:
2776 nid = spec->autocfg.hp_pins[nid];
2777 break;
2778 default:
2779 continue;
2780 }
2781 err = snd_hda_add_nid(codec, kctl, 0, nid);
2782 if (err < 0)
2783 return err;
2784 }
2785 u = knew->private_value;
2786 for (j = 0; j < 4; j++, u >>= 8) {
2787 nid = u & 0xff;
2788 if (nid == 0)
2789 continue;
2790 err = snd_hda_add_nid(codec, kctl, 0, nid);
2791 if (err < 0)
2792 return err;
2793 }
2794 }
2795 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01002796
2797 alc_free_kctls(codec); /* no longer needed */
2798
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 return 0;
2800}
2801
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002802
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803/*
2804 * initialize the codec volumes, etc
2805 */
2806
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002807/*
2808 * generic initialization of ADC, input mixers and output mixers
2809 */
2810static struct hda_verb alc880_volume_init_verbs[] = {
2811 /*
2812 * Unmute ADC0-2 and set the default input to mic-in
2813 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002814 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002815 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002816 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002817 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002818 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002819 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002821 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2822 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002823 * Note: PASD motherboards uses the Line In 2 as the input for front
2824 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002826 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002827 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2828 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2829 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2830 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2831 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2832 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2833 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002835 /*
2836 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002838 /* set vol=0 to output mixers */
2839 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2840 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2841 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2842 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2843 /* set up input amps for analog loopback */
2844 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002845 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2846 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002847 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2848 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002849 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2850 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002851 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2852 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853
2854 { }
2855};
2856
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002857/*
2858 * 3-stack pin configuration:
2859 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2860 */
2861static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2862 /*
2863 * preset connection lists of input pins
2864 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2865 */
2866 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2867 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2868 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2869
2870 /*
2871 * Set pin mode and muting
2872 */
2873 /* set front pin widgets 0x14 for output */
2874 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2875 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2876 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2877 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2878 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2879 /* Mic2 (as headphone out) for HP output */
2880 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2881 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2882 /* Line In pin widget for input */
2883 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2884 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2885 /* Line2 (as front mic) pin widget for input and vref at 80% */
2886 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2887 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2888 /* CD pin widget for input */
2889 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2890
2891 { }
2892};
2893
2894/*
2895 * 5-stack pin configuration:
2896 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2897 * line-in/side = 0x1a, f-mic = 0x1b
2898 */
2899static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2900 /*
2901 * preset connection lists of input pins
2902 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2903 */
2904 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2905 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2906
2907 /*
2908 * Set pin mode and muting
2909 */
2910 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002911 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2912 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2913 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2914 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002915 /* unmute pins for output (no gain on this amp) */
2916 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2917 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2918 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2919 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2920
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002922 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002923 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2924 /* Mic2 (as headphone out) for HP output */
2925 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002926 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002927 /* Line In pin widget for input */
2928 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2929 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2930 /* Line2 (as front mic) pin widget for input and vref at 80% */
2931 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2932 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2933 /* CD pin widget for input */
2934 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 { }
2937};
2938
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002939/*
2940 * W810 pin configuration:
2941 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2942 */
2943static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 /* hphone/speaker input selector: front DAC */
2945 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2946
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002947 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2948 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2949 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2950 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2951 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2952 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2953
2954 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002955 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 { }
2958};
2959
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002960/*
2961 * Z71V pin configuration:
2962 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2963 */
2964static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002965 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002966 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002967 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002968 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002969
Takashi Iwai16ded522005-06-10 19:58:24 +02002970 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002971 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002972 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002973 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002974
2975 { }
2976};
2977
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002978/*
2979 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002980 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2981 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002982 */
2983static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2984 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2985
Takashi Iwai16ded522005-06-10 19:58:24 +02002986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002987 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002988 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002989 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002990 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002991 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002992 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002993 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2994
Takashi Iwai16ded522005-06-10 19:58:24 +02002995 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002996 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002997 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002998 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002999 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003000 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003001 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003002 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003003 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003004
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003005 { }
3006};
Takashi Iwai16ded522005-06-10 19:58:24 +02003007
Kailang Yangccc656c2006-10-17 12:32:26 +02003008/*
3009 * Uniwill pin configuration:
3010 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3011 * line = 0x1a
3012 */
3013static struct hda_verb alc880_uniwill_init_verbs[] = {
3014 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3015
3016 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3017 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3018 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3019 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3020 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3021 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3022 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3023 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3024 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3026 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3027 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3028 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3029 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3030
3031 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3032 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3033 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3034 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3035 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3036 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3037 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3038 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3039 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3040
3041 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3042 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3043
3044 { }
3045};
3046
3047/*
3048* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003049* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003050 */
3051static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
3052 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3053
3054 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3055 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3056 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3057 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3058 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3059 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3060 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3061 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3062 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3063 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3064 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3065 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3066
3067 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3068 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3069 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3070 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3071 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3072 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3073
3074 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3075 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3076
3077 { }
3078};
3079
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003080static struct hda_verb alc880_beep_init_verbs[] = {
3081 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3082 { }
3083};
3084
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003085/* auto-toggle front mic */
3086static void alc880_uniwill_mic_automute(struct hda_codec *codec)
3087{
3088 unsigned int present;
3089 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003090
Wu Fengguang864f92b2009-11-18 12:38:02 +08003091 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003092 bits = present ? HDA_AMP_MUTE : 0;
3093 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003094}
3095
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003096static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003097{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003098 struct alc_spec *spec = codec->spec;
3099
3100 spec->autocfg.hp_pins[0] = 0x14;
3101 spec->autocfg.speaker_pins[0] = 0x15;
3102 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003103}
3104
3105static void alc880_uniwill_init_hook(struct hda_codec *codec)
3106{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003107 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003108 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003109}
3110
3111static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3112 unsigned int res)
3113{
3114 /* Looks like the unsol event is incompatible with the standard
3115 * definition. 4bit tag is placed at 28 bit!
3116 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003117 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003118 case ALC880_MIC_EVENT:
3119 alc880_uniwill_mic_automute(codec);
3120 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003121 default:
3122 alc_automute_amp_unsol_event(codec, res);
3123 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003124 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003125}
3126
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003127static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003128{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003129 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003130
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003131 spec->autocfg.hp_pins[0] = 0x14;
3132 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003133}
3134
3135static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3136{
3137 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003138
Kailang Yangccc656c2006-10-17 12:32:26 +02003139 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003140 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3141 present &= HDA_AMP_VOLMASK;
3142 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3143 HDA_AMP_VOLMASK, present);
3144 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3145 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003146}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003147
Kailang Yangccc656c2006-10-17 12:32:26 +02003148static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3149 unsigned int res)
3150{
3151 /* Looks like the unsol event is incompatible with the standard
3152 * definition. 4bit tag is placed at 28 bit!
3153 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003154 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003155 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003156 else
3157 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003158}
3159
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003160/*
3161 * F1734 pin configuration:
3162 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3163 */
3164static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003165 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003166 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3167 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3168 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3169 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3170
3171 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3172 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3173 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3174 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3175
3176 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3177 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003178 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003179 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3180 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3181 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3182 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3183 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3184 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003185
Takashi Iwai937b4162008-02-11 14:52:36 +01003186 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3187 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3188
Takashi Iwai16ded522005-06-10 19:58:24 +02003189 { }
3190};
3191
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003192/*
3193 * ASUS pin configuration:
3194 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3195 */
3196static struct hda_verb alc880_pin_asus_init_verbs[] = {
3197 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3198 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3199 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3200 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3201
3202 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3203 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3204 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3205 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3206 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3207 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3208 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3209 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3210
3211 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3212 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3213 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3214 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3215 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3216 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3217 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3218 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3219 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003220
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003221 { }
3222};
3223
3224/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003225#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3226#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003227#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003228
Kailang Yangdf694da2005-12-05 19:42:22 +01003229/* Clevo m520g init */
3230static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3231 /* headphone output */
3232 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3233 /* line-out */
3234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3236 /* Line-in */
3237 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3238 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3239 /* CD */
3240 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3241 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3242 /* Mic1 (rear panel) */
3243 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3244 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3245 /* Mic2 (front panel) */
3246 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3247 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3248 /* headphone */
3249 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3250 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3251 /* change to EAPD mode */
3252 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3253 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3254
3255 { }
3256};
3257
3258static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003259 /* change to EAPD mode */
3260 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3261 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3262
Kailang Yangdf694da2005-12-05 19:42:22 +01003263 /* Headphone output */
3264 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3265 /* Front output*/
3266 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3267 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3268
3269 /* Line In pin widget for input */
3270 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3271 /* CD pin widget for input */
3272 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3273 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3274 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3275
3276 /* change to EAPD mode */
3277 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3278 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3279
3280 { }
3281};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003282
3283/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003284 * LG m1 express dual
3285 *
3286 * Pin assignment:
3287 * Rear Line-In/Out (blue): 0x14
3288 * Build-in Mic-In: 0x15
3289 * Speaker-out: 0x17
3290 * HP-Out (green): 0x1b
3291 * Mic-In/Out (red): 0x19
3292 * SPDIF-Out: 0x1e
3293 */
3294
3295/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3296static hda_nid_t alc880_lg_dac_nids[3] = {
3297 0x05, 0x02, 0x03
3298};
3299
3300/* seems analog CD is not working */
3301static struct hda_input_mux alc880_lg_capture_source = {
3302 .num_items = 3,
3303 .items = {
3304 { "Mic", 0x1 },
3305 { "Line", 0x5 },
3306 { "Internal Mic", 0x6 },
3307 },
3308};
3309
3310/* 2,4,6 channel modes */
3311static struct hda_verb alc880_lg_ch2_init[] = {
3312 /* set line-in and mic-in to input */
3313 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3314 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3315 { }
3316};
3317
3318static struct hda_verb alc880_lg_ch4_init[] = {
3319 /* set line-in to out and mic-in to input */
3320 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3321 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3322 { }
3323};
3324
3325static struct hda_verb alc880_lg_ch6_init[] = {
3326 /* set line-in and mic-in to output */
3327 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3328 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3329 { }
3330};
3331
3332static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3333 { 2, alc880_lg_ch2_init },
3334 { 4, alc880_lg_ch4_init },
3335 { 6, alc880_lg_ch6_init },
3336};
3337
3338static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003339 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3340 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003341 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3342 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3343 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3344 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3345 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3346 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3347 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3348 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3349 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3350 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3351 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3352 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3353 {
3354 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3355 .name = "Channel Mode",
3356 .info = alc_ch_mode_info,
3357 .get = alc_ch_mode_get,
3358 .put = alc_ch_mode_put,
3359 },
3360 { } /* end */
3361};
3362
3363static struct hda_verb alc880_lg_init_verbs[] = {
3364 /* set capture source to mic-in */
3365 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3366 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3367 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3368 /* mute all amp mixer inputs */
3369 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003370 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3371 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003372 /* line-in to input */
3373 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3374 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3375 /* built-in mic */
3376 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3377 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3378 /* speaker-out */
3379 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3380 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3381 /* mic-in to input */
3382 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3383 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3384 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3385 /* HP-out */
3386 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3387 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3388 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3389 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003390 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003391 { }
3392};
3393
3394/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003395static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003396{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003397 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003398
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003399 spec->autocfg.hp_pins[0] = 0x1b;
3400 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003401}
3402
3403/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003404 * LG LW20
3405 *
3406 * Pin assignment:
3407 * Speaker-out: 0x14
3408 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003409 * Built-in Mic-In: 0x19
3410 * Line-In: 0x1b
3411 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003412 * SPDIF-Out: 0x1e
3413 */
3414
Takashi Iwaid6815182006-03-23 16:06:23 +01003415static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003416 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003417 .items = {
3418 { "Mic", 0x0 },
3419 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003420 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003421 },
3422};
3423
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003424#define alc880_lg_lw_modes alc880_threestack_modes
3425
Takashi Iwaid6815182006-03-23 16:06:23 +01003426static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003427 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3428 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3429 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3430 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3431 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3432 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3433 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3434 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3435 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3436 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003437 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3438 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3439 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3440 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003441 {
3442 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3443 .name = "Channel Mode",
3444 .info = alc_ch_mode_info,
3445 .get = alc_ch_mode_get,
3446 .put = alc_ch_mode_put,
3447 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003448 { } /* end */
3449};
3450
3451static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003452 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3453 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3454 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3455
Takashi Iwaid6815182006-03-23 16:06:23 +01003456 /* set capture source to mic-in */
3457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3458 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3459 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003460 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003461 /* speaker-out */
3462 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3463 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3464 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003465 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3466 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3467 /* mic-in to input */
3468 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3469 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3470 /* built-in mic */
3471 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3472 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3473 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003474 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003475 { }
3476};
3477
3478/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003479static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003480{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003481 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003482
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003483 spec->autocfg.hp_pins[0] = 0x1b;
3484 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003485}
3486
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003487static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3488 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3489 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3490 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3491 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3492 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3493 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3494 { } /* end */
3495};
3496
3497static struct hda_input_mux alc880_medion_rim_capture_source = {
3498 .num_items = 2,
3499 .items = {
3500 { "Mic", 0x0 },
3501 { "Internal Mic", 0x1 },
3502 },
3503};
3504
3505static struct hda_verb alc880_medion_rim_init_verbs[] = {
3506 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3507
3508 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3509 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3510
3511 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3512 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3513 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3514 /* Mic2 (as headphone out) for HP output */
3515 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3516 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3517 /* Internal Speaker */
3518 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3519 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3520
3521 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3522 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3523
3524 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3525 { }
3526};
3527
3528/* toggle speaker-output according to the hp-jack state */
3529static void alc880_medion_rim_automute(struct hda_codec *codec)
3530{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003531 struct alc_spec *spec = codec->spec;
3532 alc_automute_amp(codec);
3533 /* toggle EAPD */
3534 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003535 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3536 else
3537 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3538}
3539
3540static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3541 unsigned int res)
3542{
3543 /* Looks like the unsol event is incompatible with the standard
3544 * definition. 4bit tag is placed at 28 bit!
3545 */
3546 if ((res >> 28) == ALC880_HP_EVENT)
3547 alc880_medion_rim_automute(codec);
3548}
3549
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003550static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003551{
3552 struct alc_spec *spec = codec->spec;
3553
3554 spec->autocfg.hp_pins[0] = 0x14;
3555 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003556}
3557
Takashi Iwaicb53c622007-08-10 17:21:45 +02003558#ifdef CONFIG_SND_HDA_POWER_SAVE
3559static struct hda_amp_list alc880_loopbacks[] = {
3560 { 0x0b, HDA_INPUT, 0 },
3561 { 0x0b, HDA_INPUT, 1 },
3562 { 0x0b, HDA_INPUT, 2 },
3563 { 0x0b, HDA_INPUT, 3 },
3564 { 0x0b, HDA_INPUT, 4 },
3565 { } /* end */
3566};
3567
3568static struct hda_amp_list alc880_lg_loopbacks[] = {
3569 { 0x0b, HDA_INPUT, 1 },
3570 { 0x0b, HDA_INPUT, 6 },
3571 { 0x0b, HDA_INPUT, 7 },
3572 { } /* end */
3573};
3574#endif
3575
Takashi Iwaid6815182006-03-23 16:06:23 +01003576/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003577 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003578 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003579
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580static int alc_init(struct hda_codec *codec)
3581{
3582 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003583 unsigned int i;
3584
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003585 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003586 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003587
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003588 for (i = 0; i < spec->num_init_verbs; i++)
3589 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003590
3591 if (spec->init_hook)
3592 spec->init_hook(codec);
3593
Takashi Iwaiad358792010-03-30 18:00:59 +02003594#ifdef CONFIG_SND_HDA_POWER_SAVE
3595 if (codec->patch_ops.check_power_status)
3596 codec->patch_ops.check_power_status(codec, 0x01);
3597#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 return 0;
3599}
3600
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003601static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3602{
3603 struct alc_spec *spec = codec->spec;
3604
3605 if (spec->unsol_event)
3606 spec->unsol_event(codec, res);
3607}
3608
Takashi Iwaicb53c622007-08-10 17:21:45 +02003609#ifdef CONFIG_SND_HDA_POWER_SAVE
3610static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3611{
3612 struct alc_spec *spec = codec->spec;
3613 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3614}
3615#endif
3616
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617/*
3618 * Analog playback callbacks
3619 */
3620static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3621 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003622 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623{
3624 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003625 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3626 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627}
3628
3629static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3630 struct hda_codec *codec,
3631 unsigned int stream_tag,
3632 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003633 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634{
3635 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003636 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3637 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638}
3639
3640static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3641 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003642 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643{
3644 struct alc_spec *spec = codec->spec;
3645 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3646}
3647
3648/*
3649 * Digital out
3650 */
3651static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3652 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003653 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654{
3655 struct alc_spec *spec = codec->spec;
3656 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3657}
3658
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003659static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3660 struct hda_codec *codec,
3661 unsigned int stream_tag,
3662 unsigned int format,
3663 struct snd_pcm_substream *substream)
3664{
3665 struct alc_spec *spec = codec->spec;
3666 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3667 stream_tag, format, substream);
3668}
3669
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003670static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3671 struct hda_codec *codec,
3672 struct snd_pcm_substream *substream)
3673{
3674 struct alc_spec *spec = codec->spec;
3675 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3676}
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3679 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003680 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681{
3682 struct alc_spec *spec = codec->spec;
3683 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3684}
3685
3686/*
3687 * Analog capture
3688 */
Takashi Iwai63300792008-01-24 15:31:36 +01003689static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 struct hda_codec *codec,
3691 unsigned int stream_tag,
3692 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003693 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694{
3695 struct alc_spec *spec = codec->spec;
3696
Takashi Iwai63300792008-01-24 15:31:36 +01003697 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 stream_tag, 0, format);
3699 return 0;
3700}
3701
Takashi Iwai63300792008-01-24 15:31:36 +01003702static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003704 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705{
3706 struct alc_spec *spec = codec->spec;
3707
Takashi Iwai888afa12008-03-18 09:57:50 +01003708 snd_hda_codec_cleanup_stream(codec,
3709 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 return 0;
3711}
3712
Takashi Iwai840b64c2010-07-13 22:49:01 +02003713/* analog capture with dynamic dual-adc changes */
3714static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3715 struct hda_codec *codec,
3716 unsigned int stream_tag,
3717 unsigned int format,
3718 struct snd_pcm_substream *substream)
3719{
3720 struct alc_spec *spec = codec->spec;
3721 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
3722 spec->cur_adc_stream_tag = stream_tag;
3723 spec->cur_adc_format = format;
3724 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
3725 return 0;
3726}
3727
3728static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3729 struct hda_codec *codec,
3730 struct snd_pcm_substream *substream)
3731{
3732 struct alc_spec *spec = codec->spec;
3733 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3734 spec->cur_adc = 0;
3735 return 0;
3736}
3737
3738static struct hda_pcm_stream dualmic_pcm_analog_capture = {
3739 .substreams = 1,
3740 .channels_min = 2,
3741 .channels_max = 2,
3742 .nid = 0, /* fill later */
3743 .ops = {
3744 .prepare = dualmic_capture_pcm_prepare,
3745 .cleanup = dualmic_capture_pcm_cleanup
3746 },
3747};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748
3749/*
3750 */
3751static struct hda_pcm_stream alc880_pcm_analog_playback = {
3752 .substreams = 1,
3753 .channels_min = 2,
3754 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003755 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 .ops = {
3757 .open = alc880_playback_pcm_open,
3758 .prepare = alc880_playback_pcm_prepare,
3759 .cleanup = alc880_playback_pcm_cleanup
3760 },
3761};
3762
3763static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003764 .substreams = 1,
3765 .channels_min = 2,
3766 .channels_max = 2,
3767 /* NID is set in alc_build_pcms */
3768};
3769
3770static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3771 .substreams = 1,
3772 .channels_min = 2,
3773 .channels_max = 2,
3774 /* NID is set in alc_build_pcms */
3775};
3776
3777static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3778 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 .channels_min = 2,
3780 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003781 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003783 .prepare = alc880_alt_capture_pcm_prepare,
3784 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 },
3786};
3787
3788static struct hda_pcm_stream alc880_pcm_digital_playback = {
3789 .substreams = 1,
3790 .channels_min = 2,
3791 .channels_max = 2,
3792 /* NID is set in alc_build_pcms */
3793 .ops = {
3794 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003795 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003796 .prepare = alc880_dig_playback_pcm_prepare,
3797 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 },
3799};
3800
3801static struct hda_pcm_stream alc880_pcm_digital_capture = {
3802 .substreams = 1,
3803 .channels_min = 2,
3804 .channels_max = 2,
3805 /* NID is set in alc_build_pcms */
3806};
3807
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003808/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003809static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003810 .substreams = 0,
3811 .channels_min = 0,
3812 .channels_max = 0,
3813};
3814
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815static int alc_build_pcms(struct hda_codec *codec)
3816{
3817 struct alc_spec *spec = codec->spec;
3818 struct hda_pcm *info = spec->pcm_rec;
3819 int i;
3820
3821 codec->num_pcms = 1;
3822 codec->pcm_info = info;
3823
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003824 if (spec->no_analog)
3825 goto skip_analog;
3826
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003827 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3828 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003830
Takashi Iwai4a471b72005-12-07 13:56:29 +01003831 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003832 if (snd_BUG_ON(!spec->multiout.dac_nids))
3833 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003834 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3835 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3836 }
3837 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003838 if (snd_BUG_ON(!spec->adc_nids))
3839 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003840 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3841 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
Takashi Iwai4a471b72005-12-07 13:56:29 +01003844 if (spec->channel_mode) {
3845 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3846 for (i = 0; i < spec->num_channel_mode; i++) {
3847 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3848 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 }
3851 }
3852
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003853 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003854 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003856 snprintf(spec->stream_name_digital,
3857 sizeof(spec->stream_name_digital),
3858 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003859 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003860 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003861 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003863 if (spec->dig_out_type)
3864 info->pcm_type = spec->dig_out_type;
3865 else
3866 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003867 if (spec->multiout.dig_out_nid &&
3868 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3870 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3871 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003872 if (spec->dig_in_nid &&
3873 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3875 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3876 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003877 /* FIXME: do we need this for all Realtek codec models? */
3878 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 }
3880
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003881 if (spec->no_analog)
3882 return 0;
3883
Takashi Iwaie08a0072006-09-07 17:52:14 +02003884 /* If the use of more than one ADC is requested for the current
3885 * model, configure a second analog capture-only PCM.
3886 */
3887 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003888 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3889 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003890 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003891 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003892 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003893 if (spec->alt_dac_nid) {
3894 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3895 *spec->stream_analog_alt_playback;
3896 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3897 spec->alt_dac_nid;
3898 } else {
3899 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3900 alc_pcm_null_stream;
3901 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3902 }
3903 if (spec->num_adc_nids > 1) {
3904 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3905 *spec->stream_analog_alt_capture;
3906 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3907 spec->adc_nids[1];
3908 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3909 spec->num_adc_nids - 1;
3910 } else {
3911 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3912 alc_pcm_null_stream;
3913 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003914 }
3915 }
3916
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 return 0;
3918}
3919
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003920static inline void alc_shutup(struct hda_codec *codec)
3921{
3922 snd_hda_shutup_pins(codec);
3923}
3924
Takashi Iwai603c4012008-07-30 15:01:44 +02003925static void alc_free_kctls(struct hda_codec *codec)
3926{
3927 struct alc_spec *spec = codec->spec;
3928
3929 if (spec->kctls.list) {
3930 struct snd_kcontrol_new *kctl = spec->kctls.list;
3931 int i;
3932 for (i = 0; i < spec->kctls.used; i++)
3933 kfree(kctl[i].name);
3934 }
3935 snd_array_free(&spec->kctls);
3936}
3937
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938static void alc_free(struct hda_codec *codec)
3939{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003940 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003941
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003942 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003943 return;
3944
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003945 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02003946 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003947 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003948 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949}
3950
Hector Martinf5de24b2009-12-20 22:51:31 +01003951#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05003952static void alc_power_eapd(struct hda_codec *codec)
3953{
3954 /* We currently only handle front, HP */
3955 switch (codec->vendor_id) {
3956 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003957 set_eapd(codec, 0x0f, 0);
3958 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05003959 break;
3960 case 0x10ec0262:
3961 case 0x10ec0267:
3962 case 0x10ec0268:
3963 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003964 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05003965 case 0x10ec0272:
3966 case 0x10ec0660:
3967 case 0x10ec0662:
3968 case 0x10ec0663:
3969 case 0x10ec0862:
3970 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01003971 set_eapd(codec, 0x14, 0);
3972 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05003973 break;
3974 }
3975}
3976
Hector Martinf5de24b2009-12-20 22:51:31 +01003977static int alc_suspend(struct hda_codec *codec, pm_message_t state)
3978{
3979 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01003980 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003981 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05003982 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003983 return 0;
3984}
3985#endif
3986
Takashi Iwaie044c392008-10-27 16:56:24 +01003987#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003988static int alc_resume(struct hda_codec *codec)
3989{
Takashi Iwaie044c392008-10-27 16:56:24 +01003990 codec->patch_ops.init(codec);
3991 snd_hda_codec_resume_amp(codec);
3992 snd_hda_codec_resume_cache(codec);
Takashi Iwaiad358792010-03-30 18:00:59 +02003993#ifdef CONFIG_SND_HDA_POWER_SAVE
3994 if (codec->patch_ops.check_power_status)
3995 codec->patch_ops.check_power_status(codec, 0x01);
3996#endif
Takashi Iwaie044c392008-10-27 16:56:24 +01003997 return 0;
3998}
Takashi Iwaie044c392008-10-27 16:56:24 +01003999#endif
4000
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001/*
4002 */
4003static struct hda_codec_ops alc_patch_ops = {
4004 .build_controls = alc_build_controls,
4005 .build_pcms = alc_build_pcms,
4006 .init = alc_init,
4007 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004008 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004009#ifdef SND_HDA_NEEDS_RESUME
4010 .resume = alc_resume,
4011#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004012#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004013 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004014 .check_power_status = alc_check_power_status,
4015#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004016 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017};
4018
Kailang Yangc027ddc2010-03-19 11:33:06 +01004019/* replace the codec chip_name with the given string */
4020static int alc_codec_rename(struct hda_codec *codec, const char *name)
4021{
4022 kfree(codec->chip_name);
4023 codec->chip_name = kstrdup(name, GFP_KERNEL);
4024 if (!codec->chip_name) {
4025 alc_free(codec);
4026 return -ENOMEM;
4027 }
4028 return 0;
4029}
4030
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004031/*
4032 * Test configuration for debugging
4033 *
4034 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4035 * enum controls.
4036 */
4037#ifdef CONFIG_SND_DEBUG
4038static hda_nid_t alc880_test_dac_nids[4] = {
4039 0x02, 0x03, 0x04, 0x05
4040};
4041
4042static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004043 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004044 .items = {
4045 { "In-1", 0x0 },
4046 { "In-2", 0x1 },
4047 { "In-3", 0x2 },
4048 { "In-4", 0x3 },
4049 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004050 { "Front", 0x5 },
4051 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004052 },
4053};
4054
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004055static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004056 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004057 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004058 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004059 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004060};
4061
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004062static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4063 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004064{
4065 static char *texts[] = {
4066 "N/A", "Line Out", "HP Out",
4067 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4068 };
4069 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4070 uinfo->count = 1;
4071 uinfo->value.enumerated.items = 8;
4072 if (uinfo->value.enumerated.item >= 8)
4073 uinfo->value.enumerated.item = 7;
4074 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4075 return 0;
4076}
4077
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004078static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4079 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004080{
4081 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4082 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4083 unsigned int pin_ctl, item = 0;
4084
4085 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4086 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4087 if (pin_ctl & AC_PINCTL_OUT_EN) {
4088 if (pin_ctl & AC_PINCTL_HP_EN)
4089 item = 2;
4090 else
4091 item = 1;
4092 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4093 switch (pin_ctl & AC_PINCTL_VREFEN) {
4094 case AC_PINCTL_VREF_HIZ: item = 3; break;
4095 case AC_PINCTL_VREF_50: item = 4; break;
4096 case AC_PINCTL_VREF_GRD: item = 5; break;
4097 case AC_PINCTL_VREF_80: item = 6; break;
4098 case AC_PINCTL_VREF_100: item = 7; break;
4099 }
4100 }
4101 ucontrol->value.enumerated.item[0] = item;
4102 return 0;
4103}
4104
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004105static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4106 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004107{
4108 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4109 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4110 static unsigned int ctls[] = {
4111 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4112 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4113 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4114 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4115 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4116 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4117 };
4118 unsigned int old_ctl, new_ctl;
4119
4120 old_ctl = snd_hda_codec_read(codec, nid, 0,
4121 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4122 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4123 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004124 int val;
4125 snd_hda_codec_write_cache(codec, nid, 0,
4126 AC_VERB_SET_PIN_WIDGET_CONTROL,
4127 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004128 val = ucontrol->value.enumerated.item[0] >= 3 ?
4129 HDA_AMP_MUTE : 0;
4130 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4131 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004132 return 1;
4133 }
4134 return 0;
4135}
4136
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004137static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4138 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004139{
4140 static char *texts[] = {
4141 "Front", "Surround", "CLFE", "Side"
4142 };
4143 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4144 uinfo->count = 1;
4145 uinfo->value.enumerated.items = 4;
4146 if (uinfo->value.enumerated.item >= 4)
4147 uinfo->value.enumerated.item = 3;
4148 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4149 return 0;
4150}
4151
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004152static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4153 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004154{
4155 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4156 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4157 unsigned int sel;
4158
4159 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4160 ucontrol->value.enumerated.item[0] = sel & 3;
4161 return 0;
4162}
4163
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004164static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4165 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004166{
4167 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4168 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4169 unsigned int sel;
4170
4171 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4172 if (ucontrol->value.enumerated.item[0] != sel) {
4173 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004174 snd_hda_codec_write_cache(codec, nid, 0,
4175 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004176 return 1;
4177 }
4178 return 0;
4179}
4180
4181#define PIN_CTL_TEST(xname,nid) { \
4182 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4183 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004184 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004185 .info = alc_test_pin_ctl_info, \
4186 .get = alc_test_pin_ctl_get, \
4187 .put = alc_test_pin_ctl_put, \
4188 .private_value = nid \
4189 }
4190
4191#define PIN_SRC_TEST(xname,nid) { \
4192 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4193 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004194 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004195 .info = alc_test_pin_src_info, \
4196 .get = alc_test_pin_src_get, \
4197 .put = alc_test_pin_src_put, \
4198 .private_value = nid \
4199 }
4200
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004201static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004202 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4203 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4204 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4205 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004206 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4207 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4208 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4209 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004210 PIN_CTL_TEST("Front Pin Mode", 0x14),
4211 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4212 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4213 PIN_CTL_TEST("Side Pin Mode", 0x17),
4214 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4215 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4216 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4217 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4218 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4219 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4220 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4221 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4222 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4223 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4224 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4225 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4226 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4227 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4228 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4229 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4230 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4231 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004232 {
4233 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4234 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004235 .info = alc_ch_mode_info,
4236 .get = alc_ch_mode_get,
4237 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004238 },
4239 { } /* end */
4240};
4241
4242static struct hda_verb alc880_test_init_verbs[] = {
4243 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004244 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4245 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4246 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4247 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4248 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4249 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4250 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4251 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004252 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004253 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4254 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4255 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4256 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004257 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004258 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4259 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4260 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4261 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004262 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004263 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4264 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4265 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4266 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004267 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004268 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4269 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004270 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4271 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4272 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004273 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004274 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4275 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4276 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4277 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004278 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004279 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004280 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004281 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004282 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004283 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004284 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004285 /* Analog input/passthru */
4286 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4287 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4288 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4289 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4290 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004291 { }
4292};
4293#endif
4294
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295/*
4296 */
4297
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004298static const char *alc880_models[ALC880_MODEL_LAST] = {
4299 [ALC880_3ST] = "3stack",
4300 [ALC880_TCL_S700] = "tcl",
4301 [ALC880_3ST_DIG] = "3stack-digout",
4302 [ALC880_CLEVO] = "clevo",
4303 [ALC880_5ST] = "5stack",
4304 [ALC880_5ST_DIG] = "5stack-digout",
4305 [ALC880_W810] = "w810",
4306 [ALC880_Z71V] = "z71v",
4307 [ALC880_6ST] = "6stack",
4308 [ALC880_6ST_DIG] = "6stack-digout",
4309 [ALC880_ASUS] = "asus",
4310 [ALC880_ASUS_W1V] = "asus-w1v",
4311 [ALC880_ASUS_DIG] = "asus-dig",
4312 [ALC880_ASUS_DIG2] = "asus-dig2",
4313 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004314 [ALC880_UNIWILL_P53] = "uniwill-p53",
4315 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004316 [ALC880_F1734] = "F1734",
4317 [ALC880_LG] = "lg",
4318 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004319 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004320#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004321 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004322#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004323 [ALC880_AUTO] = "auto",
4324};
4325
4326static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004327 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004328 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4329 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4330 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4331 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4332 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4333 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4334 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4335 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004336 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4337 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004338 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4339 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4340 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4341 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4342 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4343 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4344 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4345 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4346 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4347 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004348 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004349 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4350 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4351 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004352 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004353 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004354 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4355 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004356 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4357 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004358 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4359 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4360 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4361 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004362 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4363 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004364 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004365 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004366 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004367 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004368 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4369 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004370 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004371 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004372 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004373 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004374 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004375 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004376 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004377 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004378 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004379 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4380 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004381 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004382 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4383 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4384 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4385 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004386 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4387 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004388 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004389 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004390 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4391 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004392 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4393 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4394 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004395 /* default Intel */
4396 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004397 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4398 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399 {}
4400};
4401
Takashi Iwai16ded522005-06-10 19:58:24 +02004402/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004403 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004404 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004405static struct alc_config_preset alc880_presets[] = {
4406 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004407 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004408 .init_verbs = { alc880_volume_init_verbs,
4409 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004410 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004411 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004412 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4413 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004414 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004415 .input_mux = &alc880_capture_source,
4416 },
4417 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004418 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004419 .init_verbs = { alc880_volume_init_verbs,
4420 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004421 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004422 .dac_nids = alc880_dac_nids,
4423 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004424 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4425 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004426 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004427 .input_mux = &alc880_capture_source,
4428 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004429 [ALC880_TCL_S700] = {
4430 .mixers = { alc880_tcl_s700_mixer },
4431 .init_verbs = { alc880_volume_init_verbs,
4432 alc880_pin_tcl_S700_init_verbs,
4433 alc880_gpio2_init_verbs },
4434 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4435 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004436 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4437 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004438 .hp_nid = 0x03,
4439 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4440 .channel_mode = alc880_2_jack_modes,
4441 .input_mux = &alc880_capture_source,
4442 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004443 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004444 .mixers = { alc880_three_stack_mixer,
4445 alc880_five_stack_mixer},
4446 .init_verbs = { alc880_volume_init_verbs,
4447 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004448 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4449 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004450 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4451 .channel_mode = alc880_fivestack_modes,
4452 .input_mux = &alc880_capture_source,
4453 },
4454 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004455 .mixers = { alc880_three_stack_mixer,
4456 alc880_five_stack_mixer },
4457 .init_verbs = { alc880_volume_init_verbs,
4458 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004459 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4460 .dac_nids = alc880_dac_nids,
4461 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004462 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4463 .channel_mode = alc880_fivestack_modes,
4464 .input_mux = &alc880_capture_source,
4465 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004466 [ALC880_6ST] = {
4467 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004468 .init_verbs = { alc880_volume_init_verbs,
4469 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004470 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4471 .dac_nids = alc880_6st_dac_nids,
4472 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4473 .channel_mode = alc880_sixstack_modes,
4474 .input_mux = &alc880_6stack_capture_source,
4475 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004476 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004477 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004478 .init_verbs = { alc880_volume_init_verbs,
4479 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004480 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4481 .dac_nids = alc880_6st_dac_nids,
4482 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004483 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4484 .channel_mode = alc880_sixstack_modes,
4485 .input_mux = &alc880_6stack_capture_source,
4486 },
4487 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004488 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004489 .init_verbs = { alc880_volume_init_verbs,
4490 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004491 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004492 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4493 .dac_nids = alc880_w810_dac_nids,
4494 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004495 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4496 .channel_mode = alc880_w810_modes,
4497 .input_mux = &alc880_capture_source,
4498 },
4499 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004500 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004501 .init_verbs = { alc880_volume_init_verbs,
4502 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004503 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4504 .dac_nids = alc880_z71v_dac_nids,
4505 .dig_out_nid = ALC880_DIGOUT_NID,
4506 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004507 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4508 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004509 .input_mux = &alc880_capture_source,
4510 },
4511 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004512 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004513 .init_verbs = { alc880_volume_init_verbs,
4514 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004515 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4516 .dac_nids = alc880_f1734_dac_nids,
4517 .hp_nid = 0x02,
4518 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4519 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004520 .input_mux = &alc880_f1734_capture_source,
4521 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004522 .setup = alc880_uniwill_p53_setup,
4523 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004524 },
4525 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004526 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004527 .init_verbs = { alc880_volume_init_verbs,
4528 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004529 alc880_gpio1_init_verbs },
4530 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4531 .dac_nids = alc880_asus_dac_nids,
4532 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4533 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004534 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004535 .input_mux = &alc880_capture_source,
4536 },
4537 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004538 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004539 .init_verbs = { alc880_volume_init_verbs,
4540 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004541 alc880_gpio1_init_verbs },
4542 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4543 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004544 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004545 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4546 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004547 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004548 .input_mux = &alc880_capture_source,
4549 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004550 [ALC880_ASUS_DIG2] = {
4551 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004552 .init_verbs = { alc880_volume_init_verbs,
4553 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004554 alc880_gpio2_init_verbs }, /* use GPIO2 */
4555 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4556 .dac_nids = alc880_asus_dac_nids,
4557 .dig_out_nid = ALC880_DIGOUT_NID,
4558 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4559 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004560 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004561 .input_mux = &alc880_capture_source,
4562 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004563 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004564 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004565 .init_verbs = { alc880_volume_init_verbs,
4566 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004567 alc880_gpio1_init_verbs },
4568 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4569 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004570 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004571 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4572 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004573 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004574 .input_mux = &alc880_capture_source,
4575 },
4576 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004577 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004578 .init_verbs = { alc880_volume_init_verbs,
4579 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004580 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4581 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004582 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004583 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4584 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004585 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004586 .input_mux = &alc880_capture_source,
4587 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004588 [ALC880_UNIWILL] = {
4589 .mixers = { alc880_uniwill_mixer },
4590 .init_verbs = { alc880_volume_init_verbs,
4591 alc880_uniwill_init_verbs },
4592 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4593 .dac_nids = alc880_asus_dac_nids,
4594 .dig_out_nid = ALC880_DIGOUT_NID,
4595 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4596 .channel_mode = alc880_threestack_modes,
4597 .need_dac_fix = 1,
4598 .input_mux = &alc880_capture_source,
4599 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004600 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004601 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004602 },
4603 [ALC880_UNIWILL_P53] = {
4604 .mixers = { alc880_uniwill_p53_mixer },
4605 .init_verbs = { alc880_volume_init_verbs,
4606 alc880_uniwill_p53_init_verbs },
4607 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4608 .dac_nids = alc880_asus_dac_nids,
4609 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004610 .channel_mode = alc880_threestack_modes,
4611 .input_mux = &alc880_capture_source,
4612 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004613 .setup = alc880_uniwill_p53_setup,
4614 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004615 },
4616 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004617 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004618 .init_verbs = { alc880_volume_init_verbs,
4619 alc880_uniwill_p53_init_verbs,
4620 alc880_beep_init_verbs },
4621 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4622 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004623 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004624 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4625 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004626 .input_mux = &alc880_capture_source,
4627 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004628 .setup = alc880_uniwill_p53_setup,
4629 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004630 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004631 [ALC880_CLEVO] = {
4632 .mixers = { alc880_three_stack_mixer },
4633 .init_verbs = { alc880_volume_init_verbs,
4634 alc880_pin_clevo_init_verbs },
4635 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4636 .dac_nids = alc880_dac_nids,
4637 .hp_nid = 0x03,
4638 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4639 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004640 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004641 .input_mux = &alc880_capture_source,
4642 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004643 [ALC880_LG] = {
4644 .mixers = { alc880_lg_mixer },
4645 .init_verbs = { alc880_volume_init_verbs,
4646 alc880_lg_init_verbs },
4647 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4648 .dac_nids = alc880_lg_dac_nids,
4649 .dig_out_nid = ALC880_DIGOUT_NID,
4650 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4651 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004652 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004653 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004654 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004655 .setup = alc880_lg_setup,
4656 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004657#ifdef CONFIG_SND_HDA_POWER_SAVE
4658 .loopbacks = alc880_lg_loopbacks,
4659#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004660 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004661 [ALC880_LG_LW] = {
4662 .mixers = { alc880_lg_lw_mixer },
4663 .init_verbs = { alc880_volume_init_verbs,
4664 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004665 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004666 .dac_nids = alc880_dac_nids,
4667 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004668 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4669 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004670 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004671 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004672 .setup = alc880_lg_lw_setup,
4673 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004674 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004675 [ALC880_MEDION_RIM] = {
4676 .mixers = { alc880_medion_rim_mixer },
4677 .init_verbs = { alc880_volume_init_verbs,
4678 alc880_medion_rim_init_verbs,
4679 alc_gpio2_init_verbs },
4680 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4681 .dac_nids = alc880_dac_nids,
4682 .dig_out_nid = ALC880_DIGOUT_NID,
4683 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4684 .channel_mode = alc880_2_jack_modes,
4685 .input_mux = &alc880_medion_rim_capture_source,
4686 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004687 .setup = alc880_medion_rim_setup,
4688 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004689 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004690#ifdef CONFIG_SND_DEBUG
4691 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004692 .mixers = { alc880_test_mixer },
4693 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004694 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4695 .dac_nids = alc880_test_dac_nids,
4696 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004697 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4698 .channel_mode = alc880_test_modes,
4699 .input_mux = &alc880_test_capture_source,
4700 },
4701#endif
4702};
4703
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004704/*
4705 * Automatic parse of I/O pins from the BIOS configuration
4706 */
4707
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004708enum {
4709 ALC_CTL_WIDGET_VOL,
4710 ALC_CTL_WIDGET_MUTE,
4711 ALC_CTL_BIND_MUTE,
4712};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004713static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004714 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4715 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004716 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004717};
4718
4719/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004720static int add_control(struct alc_spec *spec, int type, const char *name,
4721 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004722{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004723 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004724
Takashi Iwai603c4012008-07-30 15:01:44 +02004725 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4726 knew = snd_array_new(&spec->kctls);
4727 if (!knew)
4728 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004729 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004730 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004731 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004732 return -ENOMEM;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004733 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004734 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004735 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004736 return 0;
4737}
4738
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004739static int add_control_with_pfx(struct alc_spec *spec, int type,
4740 const char *pfx, const char *dir,
4741 const char *sfx, unsigned long val)
4742{
4743 char name[32];
4744 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
4745 return add_control(spec, type, name, val);
4746}
4747
4748#define add_pb_vol_ctrl(spec, type, pfx, val) \
4749 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
4750#define add_pb_sw_ctrl(spec, type, pfx, val) \
4751 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
4752
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004753#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4754#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4755#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4756#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004757#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4758#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4759#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4760#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4761#define ALC880_PIN_CD_NID 0x1c
4762
4763/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004764static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4765 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004766{
4767 hda_nid_t nid;
4768 int assigned[4];
4769 int i, j;
4770
4771 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004772 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004773
4774 /* check the pins hardwired to audio widget */
4775 for (i = 0; i < cfg->line_outs; i++) {
4776 nid = cfg->line_out_pins[i];
4777 if (alc880_is_fixed_pin(nid)) {
4778 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004779 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004780 assigned[idx] = 1;
4781 }
4782 }
4783 /* left pins can be connect to any audio widget */
4784 for (i = 0; i < cfg->line_outs; i++) {
4785 nid = cfg->line_out_pins[i];
4786 if (alc880_is_fixed_pin(nid))
4787 continue;
4788 /* search for an empty channel */
4789 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004790 if (!assigned[j]) {
4791 spec->multiout.dac_nids[i] =
4792 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004793 assigned[j] = 1;
4794 break;
4795 }
4796 }
4797 }
4798 spec->multiout.num_dacs = cfg->line_outs;
4799 return 0;
4800}
4801
4802/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004803static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4804 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004805{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004806 static const char *chname[4] = {
4807 "Front", "Surround", NULL /*CLFE*/, "Side"
4808 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004809 hda_nid_t nid;
4810 int i, err;
4811
4812 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004813 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004814 continue;
4815 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4816 if (i == 2) {
4817 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004818 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4819 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004820 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4821 HDA_OUTPUT));
4822 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004823 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004824 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4825 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004826 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4827 HDA_OUTPUT));
4828 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004829 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004830 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4831 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004832 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4833 HDA_INPUT));
4834 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004835 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004836 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4837 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004838 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4839 HDA_INPUT));
4840 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004841 return err;
4842 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004843 const char *pfx;
4844 if (cfg->line_outs == 1 &&
4845 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4846 pfx = "Speaker";
4847 else
4848 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004849 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004850 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4851 HDA_OUTPUT));
4852 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004853 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004854 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004855 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4856 HDA_INPUT));
4857 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004858 return err;
4859 }
4860 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004861 return 0;
4862}
4863
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004864/* add playback controls for speaker and HP outputs */
4865static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4866 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004867{
4868 hda_nid_t nid;
4869 int err;
4870
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004871 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004872 return 0;
4873
4874 if (alc880_is_fixed_pin(pin)) {
4875 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004876 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004877 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004878 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004879 else
4880 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004881 /* control HP volume/switch on the output mixer amp */
4882 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004883 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004884 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4885 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004886 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004887 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004888 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4889 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004890 return err;
4891 } else if (alc880_is_multi_pin(pin)) {
4892 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004893 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004894 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004895 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4896 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004897 return err;
4898 }
4899 return 0;
4900}
4901
4902/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004903static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4904 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004905 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004906{
Kailang Yangdf694da2005-12-05 19:42:22 +01004907 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004908
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004909 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004910 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4911 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004912 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004913 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004914 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4915 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004916 return err;
4917 return 0;
4918}
4919
Takashi Iwai05f5f472009-08-25 13:10:18 +02004920static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004921{
Takashi Iwai05f5f472009-08-25 13:10:18 +02004922 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
4923 return (pincap & AC_PINCAP_IN) != 0;
4924}
4925
4926/* create playback/capture controls for input pins */
4927static int alc_auto_create_input_ctls(struct hda_codec *codec,
4928 const struct auto_pin_cfg *cfg,
4929 hda_nid_t mixer,
4930 hda_nid_t cap1, hda_nid_t cap2)
4931{
4932 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004933 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004934 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004935
4936 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02004937 hda_nid_t pin;
4938
4939 pin = cfg->input_pins[i];
4940 if (!alc_is_input_pin(codec, pin))
4941 continue;
4942
4943 if (mixer) {
4944 idx = get_connection_index(codec, mixer, pin);
4945 if (idx >= 0) {
4946 err = new_analog_input(spec, pin,
4947 auto_pin_cfg_labels[i],
4948 idx, mixer);
4949 if (err < 0)
4950 return err;
4951 }
4952 }
4953
4954 if (!cap1)
4955 continue;
4956 idx = get_connection_index(codec, cap1, pin);
4957 if (idx < 0 && cap2)
4958 idx = get_connection_index(codec, cap2, pin);
4959 if (idx >= 0) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004960 imux->items[imux->num_items].label =
4961 auto_pin_cfg_labels[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004962 imux->items[imux->num_items].index = idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004963 imux->num_items++;
4964 }
4965 }
4966 return 0;
4967}
4968
Takashi Iwai05f5f472009-08-25 13:10:18 +02004969static int alc880_auto_create_input_ctls(struct hda_codec *codec,
4970 const struct auto_pin_cfg *cfg)
4971{
4972 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
4973}
4974
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004975static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4976 unsigned int pin_type)
4977{
4978 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4979 pin_type);
4980 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004981 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4982 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004983}
4984
Kailang Yangdf694da2005-12-05 19:42:22 +01004985static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4986 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004987 int dac_idx)
4988{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004989 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004990 /* need the manual connection? */
4991 if (alc880_is_multi_pin(nid)) {
4992 struct alc_spec *spec = codec->spec;
4993 int idx = alc880_multi_pin_idx(nid);
4994 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4995 AC_VERB_SET_CONNECT_SEL,
4996 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4997 }
4998}
4999
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005000static int get_pin_type(int line_out_type)
5001{
5002 if (line_out_type == AUTO_PIN_HP_OUT)
5003 return PIN_HP;
5004 else
5005 return PIN_OUT;
5006}
5007
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005008static void alc880_auto_init_multi_out(struct hda_codec *codec)
5009{
5010 struct alc_spec *spec = codec->spec;
5011 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005012
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005013 for (i = 0; i < spec->autocfg.line_outs; i++) {
5014 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005015 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5016 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005017 }
5018}
5019
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005020static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005021{
5022 struct alc_spec *spec = codec->spec;
5023 hda_nid_t pin;
5024
Takashi Iwai82bc9552006-03-21 11:24:42 +01005025 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005026 if (pin) /* connect to front */
5027 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005028 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005029 if (pin) /* connect to front */
5030 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5031}
5032
5033static void alc880_auto_init_analog_input(struct hda_codec *codec)
5034{
5035 struct alc_spec *spec = codec->spec;
5036 int i;
5037
5038 for (i = 0; i < AUTO_PIN_LAST; i++) {
5039 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02005040 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01005041 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005042 if (nid != ALC880_PIN_CD_NID &&
5043 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005044 snd_hda_codec_write(codec, nid, 0,
5045 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005046 AMP_OUT_MUTE);
5047 }
5048 }
5049}
5050
Takashi Iwai7f311a42010-04-09 17:32:23 +02005051static void alc880_auto_init_input_src(struct hda_codec *codec)
5052{
5053 struct alc_spec *spec = codec->spec;
5054 int c;
5055
5056 for (c = 0; c < spec->num_adc_nids; c++) {
5057 unsigned int mux_idx;
5058 const struct hda_input_mux *imux;
5059 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5060 imux = &spec->input_mux[mux_idx];
5061 if (!imux->num_items && mux_idx > 0)
5062 imux = &spec->input_mux[0];
5063 if (imux)
5064 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5065 AC_VERB_SET_CONNECT_SEL,
5066 imux->items[0].index);
5067 }
5068}
5069
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005070/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005071/* return 1 if successful, 0 if the proper config is not found,
5072 * or a negative error code
5073 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005074static int alc880_parse_auto_config(struct hda_codec *codec)
5075{
5076 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005077 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005078 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005079
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005080 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5081 alc880_ignore);
5082 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005083 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005084 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005085 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005086
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005087 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5088 if (err < 0)
5089 return err;
5090 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5091 if (err < 0)
5092 return err;
5093 err = alc880_auto_create_extra_out(spec,
5094 spec->autocfg.speaker_pins[0],
5095 "Speaker");
5096 if (err < 0)
5097 return err;
5098 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5099 "Headphone");
5100 if (err < 0)
5101 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005102 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005103 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005104 return err;
5105
5106 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5107
Takashi Iwai757899a2010-07-30 10:48:14 +02005108 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005109
Takashi Iwai603c4012008-07-30 15:01:44 +02005110 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005111 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005112
Takashi Iwaid88897e2008-10-31 15:01:37 +01005113 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005114
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005115 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005116 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005117
Kailang Yang6227cdc2010-02-25 08:36:52 +01005118 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005119
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005120 return 1;
5121}
5122
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005123/* additional initialization for auto-configuration model */
5124static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005125{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005126 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005127 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005128 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005129 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005130 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005131 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005132 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005133 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005134}
5135
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005136/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5137 * one of two digital mic pins, e.g. on ALC272
5138 */
5139static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005140{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005141 struct alc_spec *spec = codec->spec;
5142 int i;
5143
5144 for (i = 0; i < spec->num_adc_nids; i++) {
5145 hda_nid_t cap = spec->capsrc_nids ?
5146 spec->capsrc_nids[i] : spec->adc_nids[i];
5147 int iidx, eidx;
5148
5149 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5150 if (iidx < 0)
5151 continue;
5152 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5153 if (eidx < 0)
5154 continue;
5155 spec->int_mic.mux_idx = iidx;
5156 spec->ext_mic.mux_idx = eidx;
5157 if (spec->capsrc_nids)
5158 spec->capsrc_nids += i;
5159 spec->adc_nids += i;
5160 spec->num_adc_nids = 1;
5161 return;
5162 }
5163 snd_printd(KERN_INFO "hda_codec: %s: "
5164 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5165 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5166 spec->auto_mic = 0; /* disable auto-mic to be sure */
5167}
5168
Takashi Iwai840b64c2010-07-13 22:49:01 +02005169/* set the default connection to that pin */
5170static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5171{
5172 struct alc_spec *spec = codec->spec;
5173 int i;
5174
5175 for (i = 0; i < spec->num_adc_nids; i++) {
5176 hda_nid_t cap = spec->capsrc_nids ?
5177 spec->capsrc_nids[i] : spec->adc_nids[i];
5178 int idx;
5179
5180 idx = get_connection_index(codec, cap, pin);
5181 if (idx < 0)
5182 continue;
5183 /* select or unmute this route */
5184 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5185 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5186 HDA_AMP_MUTE, 0);
5187 } else {
5188 snd_hda_codec_write_cache(codec, cap, 0,
5189 AC_VERB_SET_CONNECT_SEL, idx);
5190 }
5191 return i; /* return the found index */
5192 }
5193 return -1; /* not found */
5194}
5195
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005196/* choose the ADC/MUX containing the input pin and initialize the setup */
5197static void fixup_single_adc(struct hda_codec *codec)
5198{
5199 struct alc_spec *spec = codec->spec;
Frederik Deweerdtd2db09b2010-03-05 16:34:31 +01005200 hda_nid_t pin = 0;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005201 int i;
5202
5203 /* search for the input pin; there must be only one */
5204 for (i = 0; i < AUTO_PIN_LAST; i++) {
5205 if (spec->autocfg.input_pins[i]) {
5206 pin = spec->autocfg.input_pins[i];
5207 break;
5208 }
5209 }
5210 if (!pin)
5211 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005212 i = init_capsrc_for_pin(codec, pin);
5213 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005214 /* use only this ADC */
5215 if (spec->capsrc_nids)
5216 spec->capsrc_nids += i;
5217 spec->adc_nids += i;
5218 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005219 }
5220}
5221
Takashi Iwai840b64c2010-07-13 22:49:01 +02005222/* initialize dual adcs */
5223static void fixup_dual_adc_switch(struct hda_codec *codec)
5224{
5225 struct alc_spec *spec = codec->spec;
5226 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5227 init_capsrc_for_pin(codec, spec->int_mic.pin);
5228}
5229
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005230static void set_capture_mixer(struct hda_codec *codec)
5231{
5232 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005233 static struct snd_kcontrol_new *caps[2][3] = {
5234 { alc_capture_mixer_nosrc1,
5235 alc_capture_mixer_nosrc2,
5236 alc_capture_mixer_nosrc3 },
5237 { alc_capture_mixer1,
5238 alc_capture_mixer2,
5239 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005240 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005241 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005242 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005243 int num_adcs = spec->num_adc_nids;
5244 if (spec->dual_adc_switch)
5245 fixup_dual_adc_switch(codec);
5246 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005247 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005248 else if (spec->input_mux) {
5249 if (spec->input_mux->num_items > 1)
5250 mux = 1;
5251 else if (spec->input_mux->num_items == 1)
5252 fixup_single_adc(codec);
5253 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005254 if (spec->dual_adc_switch)
5255 num_adcs = 1;
5256 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005257 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005258}
5259
Takashi Iwai66946352010-03-29 17:21:45 +02005260/* fill adc_nids (and capsrc_nids) containing all active input pins */
5261static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5262 int num_nids)
5263{
5264 struct alc_spec *spec = codec->spec;
5265 int n;
5266 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5267
5268 for (n = 0; n < num_nids; n++) {
5269 hda_nid_t adc, cap;
5270 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5271 int nconns, i, j;
5272
5273 adc = nids[n];
5274 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5275 continue;
5276 cap = adc;
5277 nconns = snd_hda_get_connections(codec, cap, conn,
5278 ARRAY_SIZE(conn));
5279 if (nconns == 1) {
5280 cap = conn[0];
5281 nconns = snd_hda_get_connections(codec, cap, conn,
5282 ARRAY_SIZE(conn));
5283 }
5284 if (nconns <= 0)
5285 continue;
5286 if (!fallback_adc) {
5287 fallback_adc = adc;
5288 fallback_cap = cap;
5289 }
5290 for (i = 0; i < AUTO_PIN_LAST; i++) {
5291 hda_nid_t nid = spec->autocfg.input_pins[i];
5292 if (!nid)
5293 continue;
5294 for (j = 0; j < nconns; j++) {
5295 if (conn[j] == nid)
5296 break;
5297 }
5298 if (j >= nconns)
5299 break;
5300 }
5301 if (i >= AUTO_PIN_LAST) {
5302 int num_adcs = spec->num_adc_nids;
5303 spec->private_adc_nids[num_adcs] = adc;
5304 spec->private_capsrc_nids[num_adcs] = cap;
5305 spec->num_adc_nids++;
5306 spec->adc_nids = spec->private_adc_nids;
5307 if (adc != cap)
5308 spec->capsrc_nids = spec->private_capsrc_nids;
5309 }
5310 }
5311 if (!spec->num_adc_nids) {
5312 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005313 " using fallback 0x%x\n",
5314 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005315 spec->private_adc_nids[0] = fallback_adc;
5316 spec->adc_nids = spec->private_adc_nids;
5317 if (fallback_adc != fallback_cap) {
5318 spec->private_capsrc_nids[0] = fallback_cap;
5319 spec->capsrc_nids = spec->private_adc_nids;
5320 }
5321 }
5322}
5323
Takashi Iwai67d634c2009-11-16 15:35:59 +01005324#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005325#define set_beep_amp(spec, nid, idx, dir) \
5326 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005327
5328static struct snd_pci_quirk beep_white_list[] = {
5329 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
5330 {}
5331};
5332
5333static inline int has_cdefine_beep(struct hda_codec *codec)
5334{
5335 struct alc_spec *spec = codec->spec;
5336 const struct snd_pci_quirk *q;
5337 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5338 if (q)
5339 return q->value;
5340 return spec->cdefine.enable_pcbeep;
5341}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005342#else
5343#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005344#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005345#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005346
5347/*
5348 * OK, here we have finally the patch for ALC880
5349 */
5350
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351static int patch_alc880(struct hda_codec *codec)
5352{
5353 struct alc_spec *spec;
5354 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005355 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005357 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 if (spec == NULL)
5359 return -ENOMEM;
5360
5361 codec->spec = spec;
5362
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005363 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5364 alc880_models,
5365 alc880_cfg_tbl);
5366 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005367 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5368 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005369 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 }
5371
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005372 if (board_config == ALC880_AUTO) {
5373 /* automatic parse from the BIOS config */
5374 err = alc880_parse_auto_config(codec);
5375 if (err < 0) {
5376 alc_free(codec);
5377 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005378 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005379 printk(KERN_INFO
5380 "hda_codec: Cannot set up configuration "
5381 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005382 board_config = ALC880_3ST;
5383 }
5384 }
5385
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005386 err = snd_hda_attach_beep_device(codec, 0x1);
5387 if (err < 0) {
5388 alc_free(codec);
5389 return err;
5390 }
5391
Kailang Yangdf694da2005-12-05 19:42:22 +01005392 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005393 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5396 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005397 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5400 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5401
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005402 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005403 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005404 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005405 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005406 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005407 if (wcap != AC_WID_AUD_IN) {
5408 spec->adc_nids = alc880_adc_nids_alt;
5409 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005410 } else {
5411 spec->adc_nids = alc880_adc_nids;
5412 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005413 }
5414 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005415 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005416 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417
Takashi Iwai2134ea42008-01-10 16:53:55 +01005418 spec->vmaster_nid = 0x0c;
5419
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005421 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005422 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005423#ifdef CONFIG_SND_HDA_POWER_SAVE
5424 if (!spec->loopback.amplist)
5425 spec->loopback.amplist = alc880_loopbacks;
5426#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427
5428 return 0;
5429}
5430
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005431
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432/*
5433 * ALC260 support
5434 */
5435
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005436static hda_nid_t alc260_dac_nids[1] = {
5437 /* front */
5438 0x02,
5439};
5440
5441static hda_nid_t alc260_adc_nids[1] = {
5442 /* ADC0 */
5443 0x04,
5444};
5445
Kailang Yangdf694da2005-12-05 19:42:22 +01005446static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005447 /* ADC1 */
5448 0x05,
5449};
5450
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005451/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5452 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5453 */
5454static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005455 /* ADC0, ADC1 */
5456 0x04, 0x05
5457};
5458
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005459#define ALC260_DIGOUT_NID 0x03
5460#define ALC260_DIGIN_NID 0x06
5461
5462static struct hda_input_mux alc260_capture_source = {
5463 .num_items = 4,
5464 .items = {
5465 { "Mic", 0x0 },
5466 { "Front Mic", 0x1 },
5467 { "Line", 0x2 },
5468 { "CD", 0x4 },
5469 },
5470};
5471
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005472/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005473 * headphone jack and the internal CD lines since these are the only pins at
5474 * which audio can appear. For flexibility, also allow the option of
5475 * recording the mixer output on the second ADC (ADC0 doesn't have a
5476 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005477 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005478static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5479 {
5480 .num_items = 3,
5481 .items = {
5482 { "Mic/Line", 0x0 },
5483 { "CD", 0x4 },
5484 { "Headphone", 0x2 },
5485 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005486 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005487 {
5488 .num_items = 4,
5489 .items = {
5490 { "Mic/Line", 0x0 },
5491 { "CD", 0x4 },
5492 { "Headphone", 0x2 },
5493 { "Mixer", 0x5 },
5494 },
5495 },
5496
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005497};
5498
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005499/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5500 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005501 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005502static struct hda_input_mux alc260_acer_capture_sources[2] = {
5503 {
5504 .num_items = 4,
5505 .items = {
5506 { "Mic", 0x0 },
5507 { "Line", 0x2 },
5508 { "CD", 0x4 },
5509 { "Headphone", 0x5 },
5510 },
5511 },
5512 {
5513 .num_items = 5,
5514 .items = {
5515 { "Mic", 0x0 },
5516 { "Line", 0x2 },
5517 { "CD", 0x4 },
5518 { "Headphone", 0x6 },
5519 { "Mixer", 0x5 },
5520 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005521 },
5522};
Michael Schwingencc959482009-02-22 18:58:45 +01005523
5524/* Maxdata Favorit 100XS */
5525static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5526 {
5527 .num_items = 2,
5528 .items = {
5529 { "Line/Mic", 0x0 },
5530 { "CD", 0x4 },
5531 },
5532 },
5533 {
5534 .num_items = 3,
5535 .items = {
5536 { "Line/Mic", 0x0 },
5537 { "CD", 0x4 },
5538 { "Mixer", 0x5 },
5539 },
5540 },
5541};
5542
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543/*
5544 * This is just place-holder, so there's something for alc_build_pcms to look
5545 * at when it calculates the maximum number of channels. ALC260 has no mixer
5546 * element which allows changing the channel mode, so the verb list is
5547 * never used.
5548 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005549static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 { 2, NULL },
5551};
5552
Kailang Yangdf694da2005-12-05 19:42:22 +01005553
5554/* Mixer combinations
5555 *
5556 * basic: base_output + input + pc_beep + capture
5557 * HP: base_output + input + capture_alt
5558 * HP_3013: hp_3013 + input + capture
5559 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005560 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005561 */
5562
5563static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005564 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005565 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005566 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5567 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5568 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5569 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5570 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005571};
Kailang Yangdf694da2005-12-05 19:42:22 +01005572
5573static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5575 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5576 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5577 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5579 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5580 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5581 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 { } /* end */
5583};
5584
Takashi Iwaibec15c32008-01-28 18:16:30 +01005585/* update HP, line and mono out pins according to the master switch */
5586static void alc260_hp_master_update(struct hda_codec *codec,
5587 hda_nid_t hp, hda_nid_t line,
5588 hda_nid_t mono)
5589{
5590 struct alc_spec *spec = codec->spec;
5591 unsigned int val = spec->master_sw ? PIN_HP : 0;
5592 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005593 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005594 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005595 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005596 val);
5597 /* mono (speaker) depending on the HP jack sense */
5598 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005599 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005600 val);
5601}
5602
5603static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5604 struct snd_ctl_elem_value *ucontrol)
5605{
5606 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5607 struct alc_spec *spec = codec->spec;
5608 *ucontrol->value.integer.value = spec->master_sw;
5609 return 0;
5610}
5611
5612static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5613 struct snd_ctl_elem_value *ucontrol)
5614{
5615 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5616 struct alc_spec *spec = codec->spec;
5617 int val = !!*ucontrol->value.integer.value;
5618 hda_nid_t hp, line, mono;
5619
5620 if (val == spec->master_sw)
5621 return 0;
5622 spec->master_sw = val;
5623 hp = (kcontrol->private_value >> 16) & 0xff;
5624 line = (kcontrol->private_value >> 8) & 0xff;
5625 mono = kcontrol->private_value & 0xff;
5626 alc260_hp_master_update(codec, hp, line, mono);
5627 return 1;
5628}
5629
5630static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5631 {
5632 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5633 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005634 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005635 .info = snd_ctl_boolean_mono_info,
5636 .get = alc260_hp_master_sw_get,
5637 .put = alc260_hp_master_sw_put,
5638 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5639 },
5640 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5641 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5642 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5643 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5644 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5645 HDA_OUTPUT),
5646 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5647 { } /* end */
5648};
5649
5650static struct hda_verb alc260_hp_unsol_verbs[] = {
5651 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5652 {},
5653};
5654
5655static void alc260_hp_automute(struct hda_codec *codec)
5656{
5657 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005658
Wu Fengguang864f92b2009-11-18 12:38:02 +08005659 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005660 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5661}
5662
5663static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5664{
5665 if ((res >> 26) == ALC880_HP_EVENT)
5666 alc260_hp_automute(codec);
5667}
5668
Kailang Yangdf694da2005-12-05 19:42:22 +01005669static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005670 {
5671 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5672 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005673 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005674 .info = snd_ctl_boolean_mono_info,
5675 .get = alc260_hp_master_sw_get,
5676 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005677 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005678 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005679 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5680 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5681 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5682 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5683 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5684 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005685 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5686 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005687 { } /* end */
5688};
5689
Kailang Yang3f878302008-08-26 13:02:23 +02005690static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5691 .ops = &snd_hda_bind_vol,
5692 .values = {
5693 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5694 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5695 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5696 0
5697 },
5698};
5699
5700static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5701 .ops = &snd_hda_bind_sw,
5702 .values = {
5703 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5704 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5705 0
5706 },
5707};
5708
5709static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5710 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5711 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5712 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5713 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5714 { } /* end */
5715};
5716
Takashi Iwaibec15c32008-01-28 18:16:30 +01005717static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5718 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5719 {},
5720};
5721
5722static void alc260_hp_3013_automute(struct hda_codec *codec)
5723{
5724 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005725
Wu Fengguang864f92b2009-11-18 12:38:02 +08005726 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005727 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005728}
5729
5730static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5731 unsigned int res)
5732{
5733 if ((res >> 26) == ALC880_HP_EVENT)
5734 alc260_hp_3013_automute(codec);
5735}
5736
Kailang Yang3f878302008-08-26 13:02:23 +02005737static void alc260_hp_3012_automute(struct hda_codec *codec)
5738{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005739 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005740
Kailang Yang3f878302008-08-26 13:02:23 +02005741 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5742 bits);
5743 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5744 bits);
5745 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5746 bits);
5747}
5748
5749static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5750 unsigned int res)
5751{
5752 if ((res >> 26) == ALC880_HP_EVENT)
5753 alc260_hp_3012_automute(codec);
5754}
5755
5756/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005757 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5758 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005759static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005760 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005761 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005762 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005763 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5764 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5765 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5766 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005767 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005768 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5769 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005770 { } /* end */
5771};
5772
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005773/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5774 * versions of the ALC260 don't act on requests to enable mic bias from NID
5775 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5776 * datasheet doesn't mention this restriction. At this stage it's not clear
5777 * whether this behaviour is intentional or is a hardware bug in chip
5778 * revisions available in early 2006. Therefore for now allow the
5779 * "Headphone Jack Mode" control to span all choices, but if it turns out
5780 * that the lack of mic bias for this NID is intentional we could change the
5781 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5782 *
5783 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5784 * don't appear to make the mic bias available from the "line" jack, even
5785 * though the NID used for this jack (0x14) can supply it. The theory is
5786 * that perhaps Acer have included blocking capacitors between the ALC260
5787 * and the output jack. If this turns out to be the case for all such
5788 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5789 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005790 *
5791 * The C20x Tablet series have a mono internal speaker which is controlled
5792 * via the chip's Mono sum widget and pin complex, so include the necessary
5793 * controls for such models. On models without a "mono speaker" the control
5794 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005795 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005796static struct snd_kcontrol_new alc260_acer_mixer[] = {
5797 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5798 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005799 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005800 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005801 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005802 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005803 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005804 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5805 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5806 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5807 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5808 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5809 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5810 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5811 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005812 { } /* end */
5813};
5814
Michael Schwingencc959482009-02-22 18:58:45 +01005815/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5816 */
5817static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5818 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5819 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5820 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5821 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5822 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5823 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5824 { } /* end */
5825};
5826
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005827/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5828 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5829 */
5830static struct snd_kcontrol_new alc260_will_mixer[] = {
5831 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5832 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5833 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5834 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5835 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5836 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5837 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5838 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5839 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5840 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005841 { } /* end */
5842};
5843
5844/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5845 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5846 */
5847static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5848 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5849 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5850 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5851 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5852 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5853 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5854 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5855 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5856 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5857 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5858 { } /* end */
5859};
5860
Kailang Yangdf694da2005-12-05 19:42:22 +01005861/*
5862 * initialization verbs
5863 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864static struct hda_verb alc260_init_verbs[] = {
5865 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005866 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005868 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005870 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005872 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005874 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005876 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005878 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005880 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005882 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5883 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005884 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 /* set connection select to line in (default select for this ADC) */
5886 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005887 /* mute capture amp left and right */
5888 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5889 /* set connection select to line in (default select for this ADC) */
5890 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005891 /* set vol=0 Line-Out mixer amp left and right */
5892 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5893 /* unmute pin widget amp left and right (no gain on this amp) */
5894 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5895 /* set vol=0 HP mixer amp left and right */
5896 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5897 /* unmute pin widget amp left and right (no gain on this amp) */
5898 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5899 /* set vol=0 Mono mixer amp left and right */
5900 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5901 /* unmute pin widget amp left and right (no gain on this amp) */
5902 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5903 /* unmute LINE-2 out pin */
5904 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005905 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5906 * Line In 2 = 0x03
5907 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005908 /* mute analog inputs */
5909 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5910 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5911 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5912 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5913 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005915 /* mute Front out path */
5916 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5917 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5918 /* mute Headphone out path */
5919 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5920 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5921 /* mute Mono out path */
5922 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5923 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 { }
5925};
5926
Takashi Iwai474167d2006-05-17 17:17:43 +02005927#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005928static struct hda_verb alc260_hp_init_verbs[] = {
5929 /* Headphone and output */
5930 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5931 /* mono output */
5932 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5933 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5934 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5935 /* Mic2 (front panel) pin widget for input and vref at 80% */
5936 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5937 /* Line In pin widget for input */
5938 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5939 /* Line-2 pin widget for output */
5940 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5941 /* CD pin widget for input */
5942 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5943 /* unmute amp left and right */
5944 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5945 /* set connection select to line in (default select for this ADC) */
5946 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5947 /* unmute Line-Out mixer amp left and right (volume = 0) */
5948 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5949 /* mute pin widget amp left and right (no gain on this amp) */
5950 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5951 /* unmute HP mixer amp left and right (volume = 0) */
5952 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5953 /* mute pin widget amp left and right (no gain on this amp) */
5954 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005955 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5956 * Line In 2 = 0x03
5957 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005958 /* mute analog inputs */
5959 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5960 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5961 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5962 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5963 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005964 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5965 /* Unmute Front out path */
5966 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5967 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5968 /* Unmute Headphone out path */
5969 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5970 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5971 /* Unmute Mono out path */
5972 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5973 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5974 { }
5975};
Takashi Iwai474167d2006-05-17 17:17:43 +02005976#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005977
5978static struct hda_verb alc260_hp_3013_init_verbs[] = {
5979 /* Line out and output */
5980 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5981 /* mono output */
5982 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5983 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5984 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5985 /* Mic2 (front panel) pin widget for input and vref at 80% */
5986 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5987 /* Line In pin widget for input */
5988 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5989 /* Headphone pin widget for output */
5990 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5991 /* CD pin widget for input */
5992 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5993 /* unmute amp left and right */
5994 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5995 /* set connection select to line in (default select for this ADC) */
5996 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5997 /* unmute Line-Out mixer amp left and right (volume = 0) */
5998 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5999 /* mute pin widget amp left and right (no gain on this amp) */
6000 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6001 /* unmute HP mixer amp left and right (volume = 0) */
6002 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6003 /* mute pin widget amp left and right (no gain on this amp) */
6004 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006005 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6006 * Line In 2 = 0x03
6007 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006008 /* mute analog inputs */
6009 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6010 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6011 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6012 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6013 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006014 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6015 /* Unmute Front out path */
6016 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6017 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6018 /* Unmute Headphone out path */
6019 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6020 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6021 /* Unmute Mono out path */
6022 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6023 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6024 { }
6025};
6026
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006027/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006028 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6029 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006030 */
6031static struct hda_verb alc260_fujitsu_init_verbs[] = {
6032 /* Disable all GPIOs */
6033 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6034 /* Internal speaker is connected to headphone pin */
6035 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6036 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6037 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006038 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6039 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6040 /* Ensure all other unused pins are disabled and muted. */
6041 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6042 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006043 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006044 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006045 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006046 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6047 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6048 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006049
Jonathan Woithef7ace402006-02-28 11:46:14 +01006050 /* Disable digital (SPDIF) pins */
6051 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6052 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006053
Kailang Yangea1fb292008-08-26 12:58:38 +02006054 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006055 * when acting as an output.
6056 */
6057 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6058
6059 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006060 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6061 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6062 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6063 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6064 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6065 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6066 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6067 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6068 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006069
Jonathan Woithef7ace402006-02-28 11:46:14 +01006070 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6071 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6072 /* Unmute Line1 pin widget output buffer since it starts as an output.
6073 * If the pin mode is changed by the user the pin mode control will
6074 * take care of enabling the pin's input/output buffers as needed.
6075 * Therefore there's no need to enable the input buffer at this
6076 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006077 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006078 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006079 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006080 * mixer ctrl)
6081 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006082 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006083
Jonathan Woithef7ace402006-02-28 11:46:14 +01006084 /* Mute capture amp left and right */
6085 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006086 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006087 * in (on mic1 pin)
6088 */
6089 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006090
Jonathan Woithef7ace402006-02-28 11:46:14 +01006091 /* Do the same for the second ADC: mute capture input amp and
6092 * set ADC connection to line in (on mic1 pin)
6093 */
6094 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6095 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006096
Jonathan Woithef7ace402006-02-28 11:46:14 +01006097 /* Mute all inputs to mixer widget (even unconnected ones) */
6098 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6099 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6100 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6101 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6102 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6103 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6104 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6105 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006106
6107 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006108};
6109
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006110/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6111 * similar laptops (adapted from Fujitsu init verbs).
6112 */
6113static struct hda_verb alc260_acer_init_verbs[] = {
6114 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6115 * the headphone jack. Turn this on and rely on the standard mute
6116 * methods whenever the user wants to turn these outputs off.
6117 */
6118 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6119 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6120 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6121 /* Internal speaker/Headphone jack is connected to Line-out pin */
6122 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6123 /* Internal microphone/Mic jack is connected to Mic1 pin */
6124 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6125 /* Line In jack is connected to Line1 pin */
6126 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006127 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6128 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006129 /* Ensure all other unused pins are disabled and muted. */
6130 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6131 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006132 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6133 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6134 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6135 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6136 /* Disable digital (SPDIF) pins */
6137 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6138 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6139
Kailang Yangea1fb292008-08-26 12:58:38 +02006140 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006141 * bus when acting as outputs.
6142 */
6143 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6144 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6145
6146 /* Start with output sum widgets muted and their output gains at min */
6147 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6148 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6149 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6150 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6151 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6152 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6153 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6154 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6155 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6156
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006157 /* Unmute Line-out pin widget amp left and right
6158 * (no equiv mixer ctrl)
6159 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006160 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006161 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6162 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006163 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6164 * inputs. If the pin mode is changed by the user the pin mode control
6165 * will take care of enabling the pin's input/output buffers as needed.
6166 * Therefore there's no need to enable the input buffer at this
6167 * stage.
6168 */
6169 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6170 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6171
6172 /* Mute capture amp left and right */
6173 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6174 /* Set ADC connection select to match default mixer setting - mic
6175 * (on mic1 pin)
6176 */
6177 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6178
6179 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006180 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006181 */
6182 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006183 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006184
6185 /* Mute all inputs to mixer widget (even unconnected ones) */
6186 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6187 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6188 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6189 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6190 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6191 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6192 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6193 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6194
6195 { }
6196};
6197
Michael Schwingencc959482009-02-22 18:58:45 +01006198/* Initialisation sequence for Maxdata Favorit 100XS
6199 * (adapted from Acer init verbs).
6200 */
6201static struct hda_verb alc260_favorit100_init_verbs[] = {
6202 /* GPIO 0 enables the output jack.
6203 * Turn this on and rely on the standard mute
6204 * methods whenever the user wants to turn these outputs off.
6205 */
6206 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6207 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6208 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6209 /* Line/Mic input jack is connected to Mic1 pin */
6210 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6211 /* Ensure all other unused pins are disabled and muted. */
6212 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6213 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6214 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6215 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6216 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6217 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6218 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6219 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6220 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6221 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6222 /* Disable digital (SPDIF) pins */
6223 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6224 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6225
6226 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6227 * bus when acting as outputs.
6228 */
6229 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6230 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6231
6232 /* Start with output sum widgets muted and their output gains at min */
6233 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6234 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6235 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6236 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6237 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6238 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6239 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6240 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6241 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6242
6243 /* Unmute Line-out pin widget amp left and right
6244 * (no equiv mixer ctrl)
6245 */
6246 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6247 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6248 * inputs. If the pin mode is changed by the user the pin mode control
6249 * will take care of enabling the pin's input/output buffers as needed.
6250 * Therefore there's no need to enable the input buffer at this
6251 * stage.
6252 */
6253 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6254
6255 /* Mute capture amp left and right */
6256 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6257 /* Set ADC connection select to match default mixer setting - mic
6258 * (on mic1 pin)
6259 */
6260 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6261
6262 /* Do similar with the second ADC: mute capture input amp and
6263 * set ADC connection to mic to match ALSA's default state.
6264 */
6265 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6266 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6267
6268 /* Mute all inputs to mixer widget (even unconnected ones) */
6269 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6270 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6271 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6275 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6277
6278 { }
6279};
6280
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006281static struct hda_verb alc260_will_verbs[] = {
6282 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6283 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6284 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6285 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6286 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6287 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6288 {}
6289};
6290
6291static struct hda_verb alc260_replacer_672v_verbs[] = {
6292 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6293 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6294 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6295
6296 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6297 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6298 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6299
6300 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6301 {}
6302};
6303
6304/* toggle speaker-output according to the hp-jack state */
6305static void alc260_replacer_672v_automute(struct hda_codec *codec)
6306{
6307 unsigned int present;
6308
6309 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006310 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006311 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006312 snd_hda_codec_write_cache(codec, 0x01, 0,
6313 AC_VERB_SET_GPIO_DATA, 1);
6314 snd_hda_codec_write_cache(codec, 0x0f, 0,
6315 AC_VERB_SET_PIN_WIDGET_CONTROL,
6316 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006317 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006318 snd_hda_codec_write_cache(codec, 0x01, 0,
6319 AC_VERB_SET_GPIO_DATA, 0);
6320 snd_hda_codec_write_cache(codec, 0x0f, 0,
6321 AC_VERB_SET_PIN_WIDGET_CONTROL,
6322 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006323 }
6324}
6325
6326static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6327 unsigned int res)
6328{
6329 if ((res >> 26) == ALC880_HP_EVENT)
6330 alc260_replacer_672v_automute(codec);
6331}
6332
Kailang Yang3f878302008-08-26 13:02:23 +02006333static struct hda_verb alc260_hp_dc7600_verbs[] = {
6334 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6335 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6336 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6337 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6338 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6339 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6340 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6341 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6342 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6343 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6344 {}
6345};
6346
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006347/* Test configuration for debugging, modelled after the ALC880 test
6348 * configuration.
6349 */
6350#ifdef CONFIG_SND_DEBUG
6351static hda_nid_t alc260_test_dac_nids[1] = {
6352 0x02,
6353};
6354static hda_nid_t alc260_test_adc_nids[2] = {
6355 0x04, 0x05,
6356};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006357/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006358 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006359 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006360 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006361static struct hda_input_mux alc260_test_capture_sources[2] = {
6362 {
6363 .num_items = 7,
6364 .items = {
6365 { "MIC1 pin", 0x0 },
6366 { "MIC2 pin", 0x1 },
6367 { "LINE1 pin", 0x2 },
6368 { "LINE2 pin", 0x3 },
6369 { "CD pin", 0x4 },
6370 { "LINE-OUT pin", 0x5 },
6371 { "HP-OUT pin", 0x6 },
6372 },
6373 },
6374 {
6375 .num_items = 8,
6376 .items = {
6377 { "MIC1 pin", 0x0 },
6378 { "MIC2 pin", 0x1 },
6379 { "LINE1 pin", 0x2 },
6380 { "LINE2 pin", 0x3 },
6381 { "CD pin", 0x4 },
6382 { "Mixer", 0x5 },
6383 { "LINE-OUT pin", 0x6 },
6384 { "HP-OUT pin", 0x7 },
6385 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006386 },
6387};
6388static struct snd_kcontrol_new alc260_test_mixer[] = {
6389 /* Output driver widgets */
6390 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6391 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6392 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6393 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6394 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6395 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6396
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006397 /* Modes for retasking pin widgets
6398 * Note: the ALC260 doesn't seem to act on requests to enable mic
6399 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6400 * mention this restriction. At this stage it's not clear whether
6401 * this behaviour is intentional or is a hardware bug in chip
6402 * revisions available at least up until early 2006. Therefore for
6403 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6404 * choices, but if it turns out that the lack of mic bias for these
6405 * NIDs is intentional we could change their modes from
6406 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6407 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006408 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6409 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6410 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6411 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6412 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6413 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6414
6415 /* Loopback mixer controls */
6416 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6417 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6418 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6419 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6420 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6421 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6422 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6423 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6424 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6425 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006426 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6427 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6428 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6429 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006430
6431 /* Controls for GPIO pins, assuming they are configured as outputs */
6432 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6433 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6434 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6435 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6436
Jonathan Woithe92621f12006-02-28 11:47:47 +01006437 /* Switches to allow the digital IO pins to be enabled. The datasheet
6438 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006439 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006440 */
6441 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6442 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6443
Jonathan Woithef8225f62008-01-08 12:16:54 +01006444 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6445 * this output to turn on an external amplifier.
6446 */
6447 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6448 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6449
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006450 { } /* end */
6451};
6452static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006453 /* Enable all GPIOs as outputs with an initial value of 0 */
6454 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6455 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6456 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6457
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006458 /* Enable retasking pins as output, initially without power amp */
6459 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6460 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6461 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6462 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6463 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6464 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6465
Jonathan Woithe92621f12006-02-28 11:47:47 +01006466 /* Disable digital (SPDIF) pins initially, but users can enable
6467 * them via a mixer switch. In the case of SPDIF-out, this initverb
6468 * payload also sets the generation to 0, output to be in "consumer"
6469 * PCM format, copyright asserted, no pre-emphasis and no validity
6470 * control.
6471 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006472 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6473 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6474
Kailang Yangea1fb292008-08-26 12:58:38 +02006475 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006476 * OUT1 sum bus when acting as an output.
6477 */
6478 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6479 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6480 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6481 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6482
6483 /* Start with output sum widgets muted and their output gains at min */
6484 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6486 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6487 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6488 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6489 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6490 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6491 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6492 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6493
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006494 /* Unmute retasking pin widget output buffers since the default
6495 * state appears to be output. As the pin mode is changed by the
6496 * user the pin mode control will take care of enabling the pin's
6497 * input/output buffers as needed.
6498 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006499 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6500 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6501 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6502 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6503 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6504 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6505 /* Also unmute the mono-out pin widget */
6506 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6507
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006508 /* Mute capture amp left and right */
6509 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006510 /* Set ADC connection select to match default mixer setting (mic1
6511 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006512 */
6513 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6514
6515 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006516 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006517 */
6518 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6519 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6520
6521 /* Mute all inputs to mixer widget (even unconnected ones) */
6522 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6523 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6524 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6525 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6526 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6527 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6530
6531 { }
6532};
6533#endif
6534
Takashi Iwai63300792008-01-24 15:31:36 +01006535#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6536#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006537
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006538#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6539#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6540
Kailang Yangdf694da2005-12-05 19:42:22 +01006541/*
6542 * for BIOS auto-configuration
6543 */
6544
6545static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006546 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006547{
6548 hda_nid_t nid_vol;
6549 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006550 int err;
6551
6552 if (nid >= 0x0f && nid < 0x11) {
6553 nid_vol = nid - 0x7;
6554 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6555 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6556 } else if (nid == 0x11) {
6557 nid_vol = nid - 0x7;
6558 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6559 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6560 } else if (nid >= 0x12 && nid <= 0x15) {
6561 nid_vol = 0x08;
6562 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6563 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6564 } else
6565 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006566
Takashi Iwai863b4512008-10-21 17:01:47 +02006567 if (!(*vol_bits & (1 << nid_vol))) {
6568 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006569 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006570 if (err < 0)
6571 return err;
6572 *vol_bits |= (1 << nid_vol);
6573 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006574 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006575 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006576 return err;
6577 return 1;
6578}
6579
6580/* add playback controls from the parsed DAC table */
6581static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6582 const struct auto_pin_cfg *cfg)
6583{
6584 hda_nid_t nid;
6585 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006586 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006587
6588 spec->multiout.num_dacs = 1;
6589 spec->multiout.dac_nids = spec->private_dac_nids;
6590 spec->multiout.dac_nids[0] = 0x02;
6591
6592 nid = cfg->line_out_pins[0];
6593 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006594 const char *pfx;
6595 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6596 pfx = "Master";
6597 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6598 pfx = "Speaker";
6599 else
6600 pfx = "Front";
6601 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006602 if (err < 0)
6603 return err;
6604 }
6605
Takashi Iwai82bc9552006-03-21 11:24:42 +01006606 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006607 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006608 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006609 if (err < 0)
6610 return err;
6611 }
6612
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006613 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006614 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006615 err = alc260_add_playback_controls(spec, nid, "Headphone",
6616 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006617 if (err < 0)
6618 return err;
6619 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006620 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006621}
6622
6623/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006624static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006625 const struct auto_pin_cfg *cfg)
6626{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006627 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006628}
6629
6630static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6631 hda_nid_t nid, int pin_type,
6632 int sel_idx)
6633{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006634 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006635 /* need the manual connection? */
6636 if (nid >= 0x12) {
6637 int idx = nid - 0x12;
6638 snd_hda_codec_write(codec, idx + 0x0b, 0,
6639 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006640 }
6641}
6642
6643static void alc260_auto_init_multi_out(struct hda_codec *codec)
6644{
6645 struct alc_spec *spec = codec->spec;
6646 hda_nid_t nid;
6647
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006648 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006649 if (nid) {
6650 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6651 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6652 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006653
Takashi Iwai82bc9552006-03-21 11:24:42 +01006654 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006655 if (nid)
6656 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6657
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006658 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006659 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006660 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006661}
Kailang Yangdf694da2005-12-05 19:42:22 +01006662
6663#define ALC260_PIN_CD_NID 0x16
6664static void alc260_auto_init_analog_input(struct hda_codec *codec)
6665{
6666 struct alc_spec *spec = codec->spec;
6667 int i;
6668
6669 for (i = 0; i < AUTO_PIN_LAST; i++) {
6670 hda_nid_t nid = spec->autocfg.input_pins[i];
6671 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006672 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006673 if (nid != ALC260_PIN_CD_NID &&
6674 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006675 snd_hda_codec_write(codec, nid, 0,
6676 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006677 AMP_OUT_MUTE);
6678 }
6679 }
6680}
6681
Takashi Iwai7f311a42010-04-09 17:32:23 +02006682#define alc260_auto_init_input_src alc880_auto_init_input_src
6683
Kailang Yangdf694da2005-12-05 19:42:22 +01006684/*
6685 * generic initialization of ADC, input mixers and output mixers
6686 */
6687static struct hda_verb alc260_volume_init_verbs[] = {
6688 /*
6689 * Unmute ADC0-1 and set the default input to mic-in
6690 */
6691 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6692 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6693 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6694 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006695
Kailang Yangdf694da2005-12-05 19:42:22 +01006696 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6697 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006698 * Note: PASD motherboards uses the Line In 2 as the input for
6699 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006700 */
6701 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006702 /* mute analog inputs */
6703 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6704 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6705 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6706 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6707 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006708
6709 /*
6710 * Set up output mixers (0x08 - 0x0a)
6711 */
6712 /* set vol=0 to output mixers */
6713 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6714 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6715 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6716 /* set up input amps for analog loopback */
6717 /* Amp Indices: DAC = 0, mixer = 1 */
6718 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6719 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6720 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6721 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6722 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6723 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006724
Kailang Yangdf694da2005-12-05 19:42:22 +01006725 { }
6726};
6727
6728static int alc260_parse_auto_config(struct hda_codec *codec)
6729{
6730 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006731 int err;
6732 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6733
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006734 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6735 alc260_ignore);
6736 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006737 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006738 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6739 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006740 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006741 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006742 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006743 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006744 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006745 return err;
6746
6747 spec->multiout.max_channels = 2;
6748
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006749 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006750 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006751 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006752 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006753
Takashi Iwaid88897e2008-10-31 15:01:37 +01006754 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006755
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006756 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006757 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006758
Kailang Yang6227cdc2010-02-25 08:36:52 +01006759 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006760
Kailang Yangdf694da2005-12-05 19:42:22 +01006761 return 1;
6762}
6763
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006764/* additional initialization for auto-configuration model */
6765static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006766{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006767 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006768 alc260_auto_init_multi_out(codec);
6769 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02006770 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02006771 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006772 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006773 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006774}
6775
Takashi Iwaicb53c622007-08-10 17:21:45 +02006776#ifdef CONFIG_SND_HDA_POWER_SAVE
6777static struct hda_amp_list alc260_loopbacks[] = {
6778 { 0x07, HDA_INPUT, 0 },
6779 { 0x07, HDA_INPUT, 1 },
6780 { 0x07, HDA_INPUT, 2 },
6781 { 0x07, HDA_INPUT, 3 },
6782 { 0x07, HDA_INPUT, 4 },
6783 { } /* end */
6784};
6785#endif
6786
Kailang Yangdf694da2005-12-05 19:42:22 +01006787/*
6788 * ALC260 configurations
6789 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006790static const char *alc260_models[ALC260_MODEL_LAST] = {
6791 [ALC260_BASIC] = "basic",
6792 [ALC260_HP] = "hp",
6793 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006794 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006795 [ALC260_FUJITSU_S702X] = "fujitsu",
6796 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006797 [ALC260_WILL] = "will",
6798 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006799 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006800#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006801 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006802#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006803 [ALC260_AUTO] = "auto",
6804};
6805
6806static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006807 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006808 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006809 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006810 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006811 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006812 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006813 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006814 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006815 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006816 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6817 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6818 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6819 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6820 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6821 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6822 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6823 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6824 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006825 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006826 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006827 {}
6828};
6829
Kailang Yangdf694da2005-12-05 19:42:22 +01006830static struct alc_config_preset alc260_presets[] = {
6831 [ALC260_BASIC] = {
6832 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006833 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006834 .init_verbs = { alc260_init_verbs },
6835 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6836 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006837 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01006838 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006839 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6840 .channel_mode = alc260_modes,
6841 .input_mux = &alc260_capture_source,
6842 },
6843 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006844 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006845 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006846 .init_verbs = { alc260_init_verbs,
6847 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006848 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6849 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006850 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6851 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006852 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6853 .channel_mode = alc260_modes,
6854 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006855 .unsol_event = alc260_hp_unsol_event,
6856 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006857 },
Kailang Yang3f878302008-08-26 13:02:23 +02006858 [ALC260_HP_DC7600] = {
6859 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006860 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006861 .init_verbs = { alc260_init_verbs,
6862 alc260_hp_dc7600_verbs },
6863 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6864 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006865 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6866 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006867 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6868 .channel_mode = alc260_modes,
6869 .input_mux = &alc260_capture_source,
6870 .unsol_event = alc260_hp_3012_unsol_event,
6871 .init_hook = alc260_hp_3012_automute,
6872 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006873 [ALC260_HP_3013] = {
6874 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006875 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006876 .init_verbs = { alc260_hp_3013_init_verbs,
6877 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006878 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6879 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006880 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6881 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006882 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6883 .channel_mode = alc260_modes,
6884 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006885 .unsol_event = alc260_hp_3013_unsol_event,
6886 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006887 },
6888 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006889 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006890 .init_verbs = { alc260_fujitsu_init_verbs },
6891 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6892 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006893 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6894 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006895 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6896 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006897 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6898 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006899 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006900 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006901 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006902 .init_verbs = { alc260_acer_init_verbs },
6903 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6904 .dac_nids = alc260_dac_nids,
6905 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6906 .adc_nids = alc260_dual_adc_nids,
6907 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6908 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006909 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6910 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006911 },
Michael Schwingencc959482009-02-22 18:58:45 +01006912 [ALC260_FAVORIT100] = {
6913 .mixers = { alc260_favorit100_mixer },
6914 .init_verbs = { alc260_favorit100_init_verbs },
6915 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6916 .dac_nids = alc260_dac_nids,
6917 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6918 .adc_nids = alc260_dual_adc_nids,
6919 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6920 .channel_mode = alc260_modes,
6921 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6922 .input_mux = alc260_favorit100_capture_sources,
6923 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006924 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006925 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006926 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6927 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6928 .dac_nids = alc260_dac_nids,
6929 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6930 .adc_nids = alc260_adc_nids,
6931 .dig_out_nid = ALC260_DIGOUT_NID,
6932 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6933 .channel_mode = alc260_modes,
6934 .input_mux = &alc260_capture_source,
6935 },
6936 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006937 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006938 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6939 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6940 .dac_nids = alc260_dac_nids,
6941 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6942 .adc_nids = alc260_adc_nids,
6943 .dig_out_nid = ALC260_DIGOUT_NID,
6944 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6945 .channel_mode = alc260_modes,
6946 .input_mux = &alc260_capture_source,
6947 .unsol_event = alc260_replacer_672v_unsol_event,
6948 .init_hook = alc260_replacer_672v_automute,
6949 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006950#ifdef CONFIG_SND_DEBUG
6951 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006952 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006953 .init_verbs = { alc260_test_init_verbs },
6954 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6955 .dac_nids = alc260_test_dac_nids,
6956 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6957 .adc_nids = alc260_test_adc_nids,
6958 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6959 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006960 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6961 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006962 },
6963#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006964};
6965
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966static int patch_alc260(struct hda_codec *codec)
6967{
6968 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006969 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006970
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006971 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972 if (spec == NULL)
6973 return -ENOMEM;
6974
6975 codec->spec = spec;
6976
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006977 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6978 alc260_models,
6979 alc260_cfg_tbl);
6980 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006981 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006982 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006983 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006984 }
6985
Kailang Yangdf694da2005-12-05 19:42:22 +01006986 if (board_config == ALC260_AUTO) {
6987 /* automatic parse from the BIOS config */
6988 err = alc260_parse_auto_config(codec);
6989 if (err < 0) {
6990 alc_free(codec);
6991 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006992 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006993 printk(KERN_INFO
6994 "hda_codec: Cannot set up configuration "
6995 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006996 board_config = ALC260_BASIC;
6997 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006999
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007000 err = snd_hda_attach_beep_device(codec, 0x1);
7001 if (err < 0) {
7002 alc_free(codec);
7003 return err;
7004 }
7005
Kailang Yangdf694da2005-12-05 19:42:22 +01007006 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007007 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007008
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7010 spec->stream_analog_capture = &alc260_pcm_analog_capture;
7011
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007012 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7013 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7014
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007015 if (!spec->adc_nids && spec->input_mux) {
7016 /* check whether NID 0x04 is valid */
7017 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007018 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007019 /* get type */
7020 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7021 spec->adc_nids = alc260_adc_nids_alt;
7022 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7023 } else {
7024 spec->adc_nids = alc260_adc_nids;
7025 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7026 }
7027 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007028 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007029 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007030
Takashi Iwai2134ea42008-01-10 16:53:55 +01007031 spec->vmaster_nid = 0x08;
7032
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007034 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007035 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007036#ifdef CONFIG_SND_HDA_POWER_SAVE
7037 if (!spec->loopback.amplist)
7038 spec->loopback.amplist = alc260_loopbacks;
7039#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007040
7041 return 0;
7042}
7043
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007044
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045/*
Takashi Iwai49535502009-06-30 15:28:30 +02007046 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047 *
7048 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7049 * configuration. Each pin widget can choose any input DACs and a mixer.
7050 * Each ADC is connected from a mixer of all inputs. This makes possible
7051 * 6-channel independent captures.
7052 *
7053 * In addition, an independent DAC for the multi-playback (not used in this
7054 * driver yet).
7055 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007056#define ALC882_DIGOUT_NID 0x06
7057#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007058#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7059#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7060#define ALC1200_DIGOUT_NID 0x10
7061
Linus Torvalds1da177e2005-04-16 15:20:36 -07007062
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007063static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064 { 8, NULL }
7065};
7066
Takashi Iwai49535502009-06-30 15:28:30 +02007067/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068static hda_nid_t alc882_dac_nids[4] = {
7069 /* front, rear, clfe, rear_surr */
7070 0x02, 0x03, 0x04, 0x05
7071};
Takashi Iwai49535502009-06-30 15:28:30 +02007072#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007073
Takashi Iwai49535502009-06-30 15:28:30 +02007074/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007075#define alc882_adc_nids alc880_adc_nids
7076#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007077#define alc883_adc_nids alc882_adc_nids_alt
7078static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7079static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7080#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081
Takashi Iwaie1406342008-02-11 18:32:32 +01007082static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7083static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007084#define alc883_capsrc_nids alc882_capsrc_nids_alt
7085static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7086#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007087
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088/* input MUX */
7089/* FIXME: should be a matrix-type input source selection */
7090
7091static struct hda_input_mux alc882_capture_source = {
7092 .num_items = 4,
7093 .items = {
7094 { "Mic", 0x0 },
7095 { "Front Mic", 0x1 },
7096 { "Line", 0x2 },
7097 { "CD", 0x4 },
7098 },
7099};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007100
Takashi Iwai49535502009-06-30 15:28:30 +02007101#define alc883_capture_source alc882_capture_source
7102
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007103static struct hda_input_mux alc889_capture_source = {
7104 .num_items = 3,
7105 .items = {
7106 { "Front Mic", 0x0 },
7107 { "Mic", 0x3 },
7108 { "Line", 0x2 },
7109 },
7110};
7111
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007112static struct hda_input_mux mb5_capture_source = {
7113 .num_items = 3,
7114 .items = {
7115 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307116 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007117 { "CD", 0x4 },
7118 },
7119};
7120
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007121static struct hda_input_mux macmini3_capture_source = {
7122 .num_items = 2,
7123 .items = {
7124 { "Line", 0x2 },
7125 { "CD", 0x4 },
7126 },
7127};
7128
Takashi Iwai49535502009-06-30 15:28:30 +02007129static struct hda_input_mux alc883_3stack_6ch_intel = {
7130 .num_items = 4,
7131 .items = {
7132 { "Mic", 0x1 },
7133 { "Front Mic", 0x0 },
7134 { "Line", 0x2 },
7135 { "CD", 0x4 },
7136 },
7137};
7138
7139static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7140 .num_items = 2,
7141 .items = {
7142 { "Mic", 0x1 },
7143 { "Line", 0x2 },
7144 },
7145};
7146
7147static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7148 .num_items = 4,
7149 .items = {
7150 { "Mic", 0x0 },
David Henningsson150b4322010-07-29 14:46:42 +02007151 { "Int Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007152 { "Line", 0x2 },
7153 { "CD", 0x4 },
7154 },
7155};
7156
7157static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7158 .num_items = 2,
7159 .items = {
7160 { "Mic", 0x0 },
7161 { "Int Mic", 0x1 },
7162 },
7163};
7164
7165static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7166 .num_items = 3,
7167 .items = {
7168 { "Mic", 0x0 },
7169 { "Front Mic", 0x1 },
7170 { "Line", 0x4 },
7171 },
7172};
7173
7174static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7175 .num_items = 2,
7176 .items = {
7177 { "Mic", 0x0 },
7178 { "Line", 0x2 },
7179 },
7180};
7181
7182static struct hda_input_mux alc889A_mb31_capture_source = {
7183 .num_items = 2,
7184 .items = {
7185 { "Mic", 0x0 },
7186 /* Front Mic (0x01) unused */
7187 { "Line", 0x2 },
7188 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007189 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007190 },
7191};
7192
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007193static struct hda_input_mux alc889A_imac91_capture_source = {
7194 .num_items = 2,
7195 .items = {
7196 { "Mic", 0x01 },
7197 { "Line", 0x2 }, /* Not sure! */
7198 },
7199};
7200
Takashi Iwai49535502009-06-30 15:28:30 +02007201/*
7202 * 2ch mode
7203 */
7204static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7205 { 2, NULL }
7206};
7207
Kailang Yangdf694da2005-12-05 19:42:22 +01007208/*
Kailang Yang272a5272007-05-14 11:00:38 +02007209 * 2ch mode
7210 */
7211static struct hda_verb alc882_3ST_ch2_init[] = {
7212 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7213 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7214 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7215 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7216 { } /* end */
7217};
7218
7219/*
Takashi Iwai49535502009-06-30 15:28:30 +02007220 * 4ch mode
7221 */
7222static struct hda_verb alc882_3ST_ch4_init[] = {
7223 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7224 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7225 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7226 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7227 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7228 { } /* end */
7229};
7230
7231/*
Kailang Yang272a5272007-05-14 11:00:38 +02007232 * 6ch mode
7233 */
7234static struct hda_verb alc882_3ST_ch6_init[] = {
7235 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7236 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7237 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7238 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7239 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7240 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7241 { } /* end */
7242};
7243
Takashi Iwai49535502009-06-30 15:28:30 +02007244static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007245 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007246 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007247 { 6, alc882_3ST_ch6_init },
7248};
7249
Takashi Iwai49535502009-06-30 15:28:30 +02007250#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7251
Kailang Yang272a5272007-05-14 11:00:38 +02007252/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307253 * 2ch mode
7254 */
7255static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7256 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7257 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7258 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7259 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7260 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7261 { } /* end */
7262};
7263
7264/*
7265 * 4ch mode
7266 */
7267static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7268 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7269 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7270 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7271 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7272 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7273 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7274 { } /* end */
7275};
7276
7277/*
7278 * 6ch mode
7279 */
7280static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7281 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7282 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7283 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7284 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7285 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7286 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7287 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7288 { } /* end */
7289};
7290
7291static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7292 { 2, alc883_3ST_ch2_clevo_init },
7293 { 4, alc883_3ST_ch4_clevo_init },
7294 { 6, alc883_3ST_ch6_clevo_init },
7295};
7296
7297
7298/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007299 * 6ch mode
7300 */
7301static struct hda_verb alc882_sixstack_ch6_init[] = {
7302 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7303 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7304 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7305 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7306 { } /* end */
7307};
7308
7309/*
7310 * 8ch mode
7311 */
7312static struct hda_verb alc882_sixstack_ch8_init[] = {
7313 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7314 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7315 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7316 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7317 { } /* end */
7318};
7319
7320static struct hda_channel_mode alc882_sixstack_modes[2] = {
7321 { 6, alc882_sixstack_ch6_init },
7322 { 8, alc882_sixstack_ch8_init },
7323};
7324
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007325
7326/* Macbook Air 2,1 */
7327
7328static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7329 { 2, NULL },
7330};
7331
Takashi Iwai87350ad2007-08-16 18:19:38 +02007332/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007333 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007334 */
7335
7336/*
7337 * 2ch mode
7338 */
7339static struct hda_verb alc885_mbp_ch2_init[] = {
7340 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7341 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7342 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7343 { } /* end */
7344};
7345
7346/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007347 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007348 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007349static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007350 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7351 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7352 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7353 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7354 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7355 { } /* end */
7356};
7357
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007358static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007359 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007360 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007361};
7362
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007363/*
7364 * 2ch
7365 * Speakers/Woofer/HP = Front
7366 * LineIn = Input
7367 */
7368static struct hda_verb alc885_mb5_ch2_init[] = {
7369 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7370 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7371 { } /* end */
7372};
7373
7374/*
7375 * 6ch mode
7376 * Speakers/HP = Front
7377 * Woofer = LFE
7378 * LineIn = Surround
7379 */
7380static struct hda_verb alc885_mb5_ch6_init[] = {
7381 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7382 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7383 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7384 { } /* end */
7385};
7386
7387static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7388 { 2, alc885_mb5_ch2_init },
7389 { 6, alc885_mb5_ch6_init },
7390};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007391
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007392#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007393
7394/*
7395 * 2ch mode
7396 */
7397static struct hda_verb alc883_4ST_ch2_init[] = {
7398 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7399 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7400 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7401 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7402 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7403 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7404 { } /* end */
7405};
7406
7407/*
7408 * 4ch mode
7409 */
7410static struct hda_verb alc883_4ST_ch4_init[] = {
7411 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7412 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7413 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7414 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7415 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7416 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7417 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7418 { } /* end */
7419};
7420
7421/*
7422 * 6ch mode
7423 */
7424static struct hda_verb alc883_4ST_ch6_init[] = {
7425 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7426 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7427 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7428 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7429 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7430 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7431 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7432 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7433 { } /* end */
7434};
7435
7436/*
7437 * 8ch mode
7438 */
7439static struct hda_verb alc883_4ST_ch8_init[] = {
7440 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7441 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7442 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7443 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7444 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7445 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7446 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7447 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7448 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7449 { } /* end */
7450};
7451
7452static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7453 { 2, alc883_4ST_ch2_init },
7454 { 4, alc883_4ST_ch4_init },
7455 { 6, alc883_4ST_ch6_init },
7456 { 8, alc883_4ST_ch8_init },
7457};
7458
7459
7460/*
7461 * 2ch mode
7462 */
7463static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7464 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7465 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7466 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7467 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7468 { } /* end */
7469};
7470
7471/*
7472 * 4ch mode
7473 */
7474static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7475 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7476 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7477 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7478 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7479 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7480 { } /* end */
7481};
7482
7483/*
7484 * 6ch mode
7485 */
7486static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7487 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7488 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7489 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7490 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7491 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7492 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7493 { } /* end */
7494};
7495
7496static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7497 { 2, alc883_3ST_ch2_intel_init },
7498 { 4, alc883_3ST_ch4_intel_init },
7499 { 6, alc883_3ST_ch6_intel_init },
7500};
7501
7502/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007503 * 2ch mode
7504 */
7505static struct hda_verb alc889_ch2_intel_init[] = {
7506 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7507 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7508 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7509 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7510 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7511 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7512 { } /* end */
7513};
7514
7515/*
Takashi Iwai49535502009-06-30 15:28:30 +02007516 * 6ch mode
7517 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007518static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007519 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7520 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7521 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7522 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7523 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007524 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7525 { } /* end */
7526};
7527
7528/*
7529 * 8ch mode
7530 */
7531static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007532 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7533 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7534 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7535 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7536 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007537 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7538 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007539 { } /* end */
7540};
7541
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007542static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7543 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007544 { 6, alc889_ch6_intel_init },
7545 { 8, alc889_ch8_intel_init },
7546};
7547
7548/*
7549 * 6ch mode
7550 */
Takashi Iwai49535502009-06-30 15:28:30 +02007551static struct hda_verb alc883_sixstack_ch6_init[] = {
7552 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7553 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7554 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7555 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7556 { } /* end */
7557};
7558
7559/*
7560 * 8ch mode
7561 */
7562static struct hda_verb alc883_sixstack_ch8_init[] = {
7563 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7564 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7565 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7566 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7567 { } /* end */
7568};
7569
7570static struct hda_channel_mode alc883_sixstack_modes[2] = {
7571 { 6, alc883_sixstack_ch6_init },
7572 { 8, alc883_sixstack_ch8_init },
7573};
7574
7575
Linus Torvalds1da177e2005-04-16 15:20:36 -07007576/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7577 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7578 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01007579static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007580 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007581 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007582 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007583 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007584 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7585 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007586 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7587 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007588 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007589 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7591 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7592 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7593 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7594 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7595 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007596 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7598 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007599 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601 { } /* end */
7602};
7603
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007604/* Macbook Air 2,1 same control for HP and internal Speaker */
7605
7606static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7607 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7608 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7609 { }
7610};
7611
7612
Takashi Iwai87350ad2007-08-16 18:19:38 +02007613static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007614 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7615 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7616 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7617 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7618 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007619 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7620 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007621 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7622 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007623 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007624 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7625 { } /* end */
7626};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007627
7628static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007629 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7630 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7631 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7632 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7633 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7634 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307635 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7636 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307637 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7638 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007639 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7640 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7641 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7642 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7643 { } /* end */
7644};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007645
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007646static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7647 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7648 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7649 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7650 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7651 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7652 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7653 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7654 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7655 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7656 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7657 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7658 { } /* end */
7659};
7660
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007661static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007662 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7663 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007664 { } /* end */
7665};
7666
7667
Kailang Yangbdd148a2007-05-08 15:19:08 +02007668static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7669 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7670 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7671 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7672 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7673 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7674 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7675 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7676 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7677 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007678 { } /* end */
7679};
7680
Kailang Yang272a5272007-05-14 11:00:38 +02007681static struct snd_kcontrol_new alc882_targa_mixer[] = {
7682 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7683 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7684 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7685 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7686 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7687 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7688 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7689 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7690 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007691 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007692 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7693 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007694 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007695 { } /* end */
7696};
7697
7698/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7699 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7700 */
7701static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7702 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7703 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7704 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7705 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7706 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7707 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7708 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7709 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7710 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7711 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7712 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7713 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007714 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007715 { } /* end */
7716};
7717
Takashi Iwai914759b2007-09-06 14:52:04 +02007718static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7719 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7720 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7721 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7722 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7723 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7724 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7725 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7726 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7727 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7728 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007729 { } /* end */
7730};
7731
Kailang Yangdf694da2005-12-05 19:42:22 +01007732static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7733 {
7734 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7735 .name = "Channel Mode",
7736 .info = alc_ch_mode_info,
7737 .get = alc_ch_mode_get,
7738 .put = alc_ch_mode_put,
7739 },
7740 { } /* end */
7741};
7742
Takashi Iwai49535502009-06-30 15:28:30 +02007743static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007744 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007745 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007747 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007748 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007750 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007751 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7752 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007754 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7755 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007756
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007757 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007758 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007759 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007760 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007761 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007762 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007763 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007765 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007766 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007767 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007768 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007769 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007770 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007771 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007773 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007774 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007775 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7776 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007777 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007778 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7779 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007780 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007781 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7782 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7783 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7784 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7785 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007787 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007788
7789 /* FIXME: use matrix-type input source selection */
7790 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007791 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007792 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007794 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007795 /* ADC2: mute amp left and right */
7796 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007797 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007798 /* ADC3: mute amp left and right */
7799 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007800 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801
7802 { }
7803};
7804
Takashi Iwai49535502009-06-30 15:28:30 +02007805static struct hda_verb alc882_adc1_init_verbs[] = {
7806 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7807 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7808 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7809 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7810 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7811 /* ADC1: mute amp left and right */
7812 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7813 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7814 { }
7815};
7816
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007817static struct hda_verb alc882_eapd_verbs[] = {
7818 /* change to EAPD mode */
7819 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007820 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007821 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007822};
7823
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007824static struct hda_verb alc889_eapd_verbs[] = {
7825 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7826 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7827 { }
7828};
7829
Wu Fengguang6732bd02009-07-30 09:19:14 +02007830static struct hda_verb alc_hp15_unsol_verbs[] = {
7831 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7832 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7833 {}
7834};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007835
7836static struct hda_verb alc885_init_verbs[] = {
7837 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01007838 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7839 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007840 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007841 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7842 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007843 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007844 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7845 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007846 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007847 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7848 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007849
7850 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007851 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007852 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7853 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7854 /* Front Pin: output 0 (0x0c) */
7855 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7856 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7857 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7858 /* Rear Pin: output 1 (0x0d) */
7859 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7860 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7861 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7862 /* CLFE Pin: output 2 (0x0e) */
7863 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7864 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7865 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7866 /* Side Pin: output 3 (0x0f) */
7867 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7868 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7869 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7870 /* Mic (rear) pin: input vref at 80% */
7871 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7872 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7873 /* Front Mic pin: input vref at 80% */
7874 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7875 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7876 /* Line In pin: input */
7877 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7878 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7879
7880 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7881 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01007882 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007883 /* Input mixer2 */
7884 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007885 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01007886 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007887 /* ADC2: mute amp left and right */
7888 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7889 /* ADC3: mute amp left and right */
7890 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7891
7892 { }
7893};
7894
7895static struct hda_verb alc885_init_input_verbs[] = {
7896 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7897 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7898 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7899 { }
7900};
7901
7902
7903/* Unmute Selector 24h and set the default input to front mic */
7904static struct hda_verb alc889_init_input_verbs[] = {
7905 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7906 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7907 { }
7908};
7909
7910
Takashi Iwai49535502009-06-30 15:28:30 +02007911#define alc883_init_verbs alc882_base_init_verbs
7912
Tobin Davis9102cd12006-12-15 10:02:12 +01007913/* Mac Pro test */
7914static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7915 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7916 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7917 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7918 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7919 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007920 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007921 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7922 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007923 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007924 { } /* end */
7925};
7926
7927static struct hda_verb alc882_macpro_init_verbs[] = {
7928 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7929 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7930 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7931 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7932 /* Front Pin: output 0 (0x0c) */
7933 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7934 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7935 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7936 /* Front Mic pin: input vref at 80% */
7937 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7938 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7939 /* Speaker: output */
7940 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7941 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7942 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7943 /* Headphone output (output 0 - 0x0c) */
7944 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7945 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7946 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7947
7948 /* FIXME: use matrix-type input source selection */
7949 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7950 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7951 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7952 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7953 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7954 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7955 /* Input mixer2 */
7956 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7957 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7958 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7959 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7960 /* Input mixer3 */
7961 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7962 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7963 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7964 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7965 /* ADC1: mute amp left and right */
7966 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7967 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7968 /* ADC2: mute amp left and right */
7969 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7970 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7971 /* ADC3: mute amp left and right */
7972 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7973 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7974
7975 { }
7976};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007977
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007978/* Macbook 5,1 */
7979static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007980 /* DACs */
7981 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7982 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7983 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7984 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007985 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007986 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7987 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7988 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007989 /* Surround mixer */
7990 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7991 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7992 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7993 /* LFE mixer */
7994 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7995 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7996 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7997 /* HP mixer */
7998 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7999 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8000 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8001 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008002 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8003 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008004 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8005 /* LFE Pin (0x0e) */
8006 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8007 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8008 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8009 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008010 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8011 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008012 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308013 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008014 /* Front Mic pin: input vref at 80% */
8015 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8016 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8017 /* Line In pin */
8018 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8019 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8020
Alex Murrayb8f171e2010-06-14 12:08:43 +09308021 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8022 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8023 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008024 { }
8025};
8026
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008027/* Macmini 3,1 */
8028static struct hda_verb alc885_macmini3_init_verbs[] = {
8029 /* DACs */
8030 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8031 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8032 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8033 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8034 /* Front mixer */
8035 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8036 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8037 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8038 /* Surround mixer */
8039 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8040 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8041 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8042 /* LFE mixer */
8043 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8044 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8045 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8046 /* HP mixer */
8047 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8048 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8049 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8050 /* Front Pin (0x0c) */
8051 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8052 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8053 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8054 /* LFE Pin (0x0e) */
8055 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8056 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8057 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8058 /* HP Pin (0x0f) */
8059 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8060 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8061 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8062 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8063 /* Line In pin */
8064 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8065 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8066
8067 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8068 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8069 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8070 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8071 { }
8072};
8073
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008074
8075static struct hda_verb alc885_mba21_init_verbs[] = {
8076 /*Internal and HP Speaker Mixer*/
8077 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8078 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8079 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8080 /*Internal Speaker Pin (0x0c)*/
8081 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8082 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8083 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8084 /* HP Pin: output 0 (0x0e) */
8085 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8086 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8087 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8088 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8089 /* Line in (is hp when jack connected)*/
8090 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8091 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8092
8093 { }
8094 };
8095
8096
Takashi Iwai87350ad2007-08-16 18:19:38 +02008097/* Macbook Pro rev3 */
8098static struct hda_verb alc885_mbp3_init_verbs[] = {
8099 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8100 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8101 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8102 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8103 /* Rear mixer */
8104 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8105 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8106 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008107 /* HP mixer */
8108 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8109 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8110 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008111 /* Front Pin: output 0 (0x0c) */
8112 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8113 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8114 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008115 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008116 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008117 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8118 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008119 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8120 /* Mic (rear) pin: input vref at 80% */
8121 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8122 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8123 /* Front Mic pin: input vref at 80% */
8124 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8125 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8126 /* Line In pin: use output 1 when in LineOut mode */
8127 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8128 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8129 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8130
8131 /* FIXME: use matrix-type input source selection */
8132 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8133 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8134 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8135 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8136 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8137 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8138 /* Input mixer2 */
8139 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8140 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8141 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8142 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8143 /* Input mixer3 */
8144 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8145 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8146 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8147 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8148 /* ADC1: mute amp left and right */
8149 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8150 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8151 /* ADC2: mute amp left and right */
8152 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8153 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8154 /* ADC3: mute amp left and right */
8155 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8156 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8157
8158 { }
8159};
8160
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008161/* iMac 9,1 */
8162static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008163 /* Internal Speaker Pin (0x0c) */
8164 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8165 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8166 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8167 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8168 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8169 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8170 /* HP Pin: Rear */
8171 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8172 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8173 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8174 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8175 /* Line in Rear */
8176 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8177 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8178 /* Front Mic pin: input vref at 80% */
8179 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8180 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008181 /* Rear mixer */
8182 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8183 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8184 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008185 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8186 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8187 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8188 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8189 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008190 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8191 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8192 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8193 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008194 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008195 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8196 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8197 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8198 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008199 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008200 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8201 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8202 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8203 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008204 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008205 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8206 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008207 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008208 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8209 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008210 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008211 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8212 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008213 { }
8214};
8215
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008216/* iMac 24 mixer. */
8217static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8218 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8219 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8220 { } /* end */
8221};
8222
8223/* iMac 24 init verbs. */
8224static struct hda_verb alc885_imac24_init_verbs[] = {
8225 /* Internal speakers: output 0 (0x0c) */
8226 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8227 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8228 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8229 /* Internal speakers: output 0 (0x0c) */
8230 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8231 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8232 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8233 /* Headphone: output 0 (0x0c) */
8234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8237 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8238 /* Front Mic: input vref at 80% */
8239 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8240 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8241 { }
8242};
8243
8244/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008245static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008246{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008247 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008248
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008249 spec->autocfg.hp_pins[0] = 0x14;
8250 spec->autocfg.speaker_pins[0] = 0x18;
8251 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008252}
8253
Takashi Iwai9d54f082010-02-22 08:34:40 +01008254#define alc885_mb5_setup alc885_imac24_setup
8255#define alc885_macmini3_setup alc885_imac24_setup
8256
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008257/* Macbook Air 2,1 */
8258static void alc885_mba21_setup(struct hda_codec *codec)
8259{
8260 struct alc_spec *spec = codec->spec;
8261
8262 spec->autocfg.hp_pins[0] = 0x14;
8263 spec->autocfg.speaker_pins[0] = 0x18;
8264}
8265
8266
8267
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008268static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008269{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008270 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008271
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008272 spec->autocfg.hp_pins[0] = 0x15;
8273 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008274}
8275
Takashi Iwai9d54f082010-02-22 08:34:40 +01008276static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308277{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008278 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308279
Takashi Iwai9d54f082010-02-22 08:34:40 +01008280 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008281 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008282 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008283}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008284
Kailang Yang272a5272007-05-14 11:00:38 +02008285static struct hda_verb alc882_targa_verbs[] = {
8286 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8287 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8288
8289 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8290 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008291
Kailang Yang272a5272007-05-14 11:00:38 +02008292 {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
8296 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008297 { } /* end */
8298};
8299
8300/* toggle speaker-output according to the hp-jack state */
8301static void alc882_targa_automute(struct hda_codec *codec)
8302{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008303 struct alc_spec *spec = codec->spec;
8304 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008305 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008306 spec->jack_present ? 1 : 3);
8307}
8308
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008309static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008310{
8311 struct alc_spec *spec = codec->spec;
8312
8313 spec->autocfg.hp_pins[0] = 0x14;
8314 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008315}
8316
8317static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8318{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008319 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008320 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008321}
8322
8323static struct hda_verb alc882_asus_a7j_verbs[] = {
8324 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8325 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8326
8327 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8328 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8329 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008330
Kailang Yang272a5272007-05-14 11:00:38 +02008331 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8332 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8333 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8334
8335 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8336 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8337 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8338 { } /* end */
8339};
8340
Takashi Iwai914759b2007-09-06 14:52:04 +02008341static struct hda_verb alc882_asus_a7m_verbs[] = {
8342 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8343 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8344
8345 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8346 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8347 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008348
Takashi Iwai914759b2007-09-06 14:52:04 +02008349 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8350 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8351 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8352
8353 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8354 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8355 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8356 { } /* end */
8357};
8358
Tobin Davis9102cd12006-12-15 10:02:12 +01008359static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8360{
8361 unsigned int gpiostate, gpiomask, gpiodir;
8362
8363 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8364 AC_VERB_GET_GPIO_DATA, 0);
8365
8366 if (!muted)
8367 gpiostate |= (1 << pin);
8368 else
8369 gpiostate &= ~(1 << pin);
8370
8371 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8372 AC_VERB_GET_GPIO_MASK, 0);
8373 gpiomask |= (1 << pin);
8374
8375 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8376 AC_VERB_GET_GPIO_DIRECTION, 0);
8377 gpiodir |= (1 << pin);
8378
8379
8380 snd_hda_codec_write(codec, codec->afg, 0,
8381 AC_VERB_SET_GPIO_MASK, gpiomask);
8382 snd_hda_codec_write(codec, codec->afg, 0,
8383 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8384
8385 msleep(1);
8386
8387 snd_hda_codec_write(codec, codec->afg, 0,
8388 AC_VERB_SET_GPIO_DATA, gpiostate);
8389}
8390
Takashi Iwai7debbe52007-08-16 15:01:03 +02008391/* set up GPIO at initialization */
8392static void alc885_macpro_init_hook(struct hda_codec *codec)
8393{
8394 alc882_gpio_mute(codec, 0, 0);
8395 alc882_gpio_mute(codec, 1, 0);
8396}
8397
8398/* set up GPIO and update auto-muting at initialization */
8399static void alc885_imac24_init_hook(struct hda_codec *codec)
8400{
8401 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008402 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008403}
8404
Kailang Yangdf694da2005-12-05 19:42:22 +01008405/*
8406 * generic initialization of ADC, input mixers and output mixers
8407 */
Takashi Iwai49535502009-06-30 15:28:30 +02008408static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008409 /*
8410 * Unmute ADC0-2 and set the default input to mic-in
8411 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008412 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8413 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8414 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8415 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8416
Kailang Yangdf694da2005-12-05 19:42:22 +01008417 /*
8418 * Set up output mixers (0x0c - 0x0f)
8419 */
8420 /* set vol=0 to output mixers */
8421 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8422 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8423 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8424 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8425 /* set up input amps for analog loopback */
8426 /* Amp Indices: DAC = 0, mixer = 1 */
8427 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8428 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8429 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8430 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8431 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8432 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8433 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8434 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8435 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8436 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8437
8438 /* FIXME: use matrix-type input source selection */
8439 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008440 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008441 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008442 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008443 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008444 { }
8445};
8446
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008447/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8448static struct hda_verb alc889A_mb31_ch2_init[] = {
8449 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8450 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8451 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8452 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8453 { } /* end */
8454};
8455
8456/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8457static struct hda_verb alc889A_mb31_ch4_init[] = {
8458 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8459 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8460 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8461 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8462 { } /* end */
8463};
8464
8465/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8466static struct hda_verb alc889A_mb31_ch5_init[] = {
8467 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8468 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8469 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8470 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8471 { } /* end */
8472};
8473
8474/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8475static struct hda_verb alc889A_mb31_ch6_init[] = {
8476 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8477 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8478 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8479 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8480 { } /* end */
8481};
8482
8483static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8484 { 2, alc889A_mb31_ch2_init },
8485 { 4, alc889A_mb31_ch4_init },
8486 { 5, alc889A_mb31_ch5_init },
8487 { 6, alc889A_mb31_ch6_init },
8488};
8489
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008490static struct hda_verb alc883_medion_eapd_verbs[] = {
8491 /* eanable EAPD on medion laptop */
8492 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8493 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8494 { }
8495};
8496
Takashi Iwai49535502009-06-30 15:28:30 +02008497#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008498
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008499static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8500 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8501 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8502 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8503 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8504 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8505 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8506 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8507 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8508 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8509 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8510 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8511 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8512 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008513 { } /* end */
8514};
8515
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008516static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008517 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8518 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8519 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8520 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8521 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8522 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8523 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8524 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8525 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8526 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008527 { } /* end */
8528};
8529
Jiang zhefb97dc62008-03-06 11:07:11 +01008530static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8531 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8532 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8533 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8534 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8535 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8536 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8537 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8538 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8539 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8540 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008541 { } /* end */
8542};
8543
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008544static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8545 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8546 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8547 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8548 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8549 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8550 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8551 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8552 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008553 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008554 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8555 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008556 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008557 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008558 { } /* end */
8559};
8560
8561static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8562 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8563 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8564 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8565 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8566 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8567 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8568 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8569 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8570 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8571 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8572 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8573 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8574 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8575 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008576 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008577 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8578 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008579 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008580 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008581 { } /* end */
8582};
8583
Jiang zhe17bba1b2008-06-04 12:11:07 +02008584static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8585 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8586 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8587 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8588 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8589 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8590 HDA_OUTPUT),
8591 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8592 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8593 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8594 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8595 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8596 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8597 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8598 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8599 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8600 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8601 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8602 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8603 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8604 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008605 { } /* end */
8606};
8607
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008608static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8609 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8610 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8611 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8612 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8613 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8614 HDA_OUTPUT),
8615 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8616 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8617 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8618 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8619 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8620 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8621 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8622 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8623 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8624 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8625 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8626 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8627 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8628 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8629 { } /* end */
8630};
8631
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008632static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008633 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008634 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008635 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008636 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008637 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8638 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008639 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8640 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008641 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8642 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8643 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8644 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8645 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008647 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008648 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8649 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008650 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008651 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008652 { } /* end */
8653};
8654
Sasha Alexandrc2592492009-06-16 14:52:54 -04008655static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008656 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008657 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008658 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008659 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008660 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8661 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8662 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8663 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8664 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8665 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8666 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8667 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8668 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8669 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8670 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008671 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008672 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008673 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008674};
Kailang Yangccc656c2006-10-17 12:32:26 +02008675
Sasha Alexandrc2592492009-06-16 14:52:54 -04008676static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008677 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008678 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008679 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008680 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008681 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8682 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8683 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008684 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008685 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008686 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8687 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8688 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008689 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008690};
Kailang Yangccc656c2006-10-17 12:32:26 +02008691
Takashi Iwaib99dba32009-09-17 18:23:00 +02008692static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8693 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8694 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8695 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8696 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8697 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8698 { } /* end */
8699};
8700
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008701static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8702 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8703 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008704 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8705 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008706 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8707 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8708 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8709 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008710 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008711};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008712
Kailang Yang272a5272007-05-14 11:00:38 +02008713static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8714 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8715 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8716 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8717 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8718 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8719 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8720 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson150b4322010-07-29 14:46:42 +02008721 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8722 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008723 { } /* end */
8724};
8725
8726static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8727 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8728 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8729 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8730 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8731 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8732 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8733 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8734 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8735 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008736 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008737};
Kailang Yang272a5272007-05-14 11:00:38 +02008738
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02008739static struct snd_kcontrol_new alc883_medion_wim2160_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_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8743 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
8744 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
8745 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
8746 { } /* end */
8747};
8748
8749static struct hda_verb alc883_medion_wim2160_verbs[] = {
8750 /* Unmute front mixer */
8751 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8752 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8753
8754 /* Set speaker pin to front mixer */
8755 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8756
8757 /* Init headphone pin */
8758 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8759 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8760 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8761 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8762
8763 { } /* end */
8764};
8765
8766/* toggle speaker-output according to the hp-jack state */
8767static void alc883_medion_wim2160_setup(struct hda_codec *codec)
8768{
8769 struct alc_spec *spec = codec->spec;
8770
8771 spec->autocfg.hp_pins[0] = 0x1a;
8772 spec->autocfg.speaker_pins[0] = 0x15;
8773}
8774
Tobin Davis2880a862007-08-07 11:50:26 +02008775static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008776 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8777 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008778 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008779 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8780 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008781 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8782 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8783 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008784 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008785};
Tobin Davis2880a862007-08-07 11:50:26 +02008786
Tony Vroond2fd4b02009-06-21 00:40:10 +01008787static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8788 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008789 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008790 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8791 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008792 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8793 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8794 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8795 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8796 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8797 { } /* end */
8798};
8799
Kailang Yange2757d52008-08-26 13:17:46 +02008800static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8801 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8802 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8803 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8804 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8805 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8806 0x0d, 1, 0x0, HDA_OUTPUT),
8807 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8808 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8809 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8810 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8811 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008812 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8813 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8814 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8815 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8816 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8817 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8818 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8819 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8820 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8821 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008822 { } /* end */
8823};
8824
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008825static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8826 /* Output mixers */
8827 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8828 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8829 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8830 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8831 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8832 HDA_OUTPUT),
8833 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8834 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8835 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8836 /* Output switches */
8837 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8838 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8839 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8840 /* Boost mixers */
8841 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8842 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8843 /* Input mixers */
8844 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8845 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8846 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8847 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8848 { } /* end */
8849};
8850
Guido Günther3e1647c2009-06-05 00:47:26 +02008851static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8852 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8853 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8854 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8855 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8856 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8857 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8858 { } /* end */
8859};
8860
Kailang Yange2757d52008-08-26 13:17:46 +02008861static struct hda_bind_ctls alc883_bind_cap_vol = {
8862 .ops = &snd_hda_bind_vol,
8863 .values = {
8864 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8865 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8866 0
8867 },
8868};
8869
8870static struct hda_bind_ctls alc883_bind_cap_switch = {
8871 .ops = &snd_hda_bind_sw,
8872 .values = {
8873 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8874 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8875 0
8876 },
8877};
8878
8879static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8880 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8881 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8882 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8883 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8884 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8885 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8886 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8887 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008888 { } /* end */
8889};
8890
8891static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008892 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8893 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8894 {
8895 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8896 /* .name = "Capture Source", */
8897 .name = "Input Source",
8898 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008899 .info = alc_mux_enum_info,
8900 .get = alc_mux_enum_get,
8901 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008902 },
8903 { } /* end */
8904};
8905
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008906static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8907 {
8908 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8909 .name = "Channel Mode",
8910 .info = alc_ch_mode_info,
8911 .get = alc_ch_mode_get,
8912 .put = alc_ch_mode_put,
8913 },
8914 { } /* end */
8915};
8916
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008917/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008918static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008919{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008920 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008921
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008922 spec->autocfg.hp_pins[0] = 0x15;
8923 spec->autocfg.speaker_pins[0] = 0x14;
8924 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008925}
8926
8927/* auto-toggle front mic */
8928/*
8929static void alc883_mitac_mic_automute(struct hda_codec *codec)
8930{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008931 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008932
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008933 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8934}
8935*/
8936
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008937static struct hda_verb alc883_mitac_verbs[] = {
8938 /* HP */
8939 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8940 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8941 /* Subwoofer */
8942 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8943 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8944
8945 /* enable unsolicited event */
8946 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8947 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8948
8949 { } /* end */
8950};
8951
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308952static struct hda_verb alc883_clevo_m540r_verbs[] = {
8953 /* HP */
8954 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8955 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8956 /* Int speaker */
8957 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8958
8959 /* enable unsolicited event */
8960 /*
8961 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8962 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8963 */
8964
8965 { } /* end */
8966};
8967
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008968static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008969 /* HP */
8970 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8971 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8972 /* Int speaker */
8973 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8974 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8975
8976 /* enable unsolicited event */
8977 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008978 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008979
8980 { } /* end */
8981};
8982
Jiang zhefb97dc62008-03-06 11:07:11 +01008983static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8984 /* HP */
8985 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8987 /* Subwoofer */
8988 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8989 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8990
8991 /* enable unsolicited event */
8992 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8993
8994 { } /* end */
8995};
8996
Sasha Alexandrc2592492009-06-16 14:52:54 -04008997static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008998 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8999 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9000
9001 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9002 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009003
David Heidelberger64a8be72009-06-08 16:15:18 +02009004/* Connect Line-Out side jack (SPDIF) to Side */
9005 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9006 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9007 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9008/* Connect Mic jack to CLFE */
9009 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9010 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9011 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9012/* Connect Line-in jack to Surround */
9013 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9014 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9015 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9016/* Connect HP out jack to Front */
9017 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9018 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9019 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009020
9021 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009022
9023 { } /* end */
9024};
9025
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009026static struct hda_verb alc883_lenovo_101e_verbs[] = {
9027 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9028 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9029 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9030 { } /* end */
9031};
9032
Kailang Yang272a5272007-05-14 11:00:38 +02009033static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9034 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9035 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9036 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9037 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9038 { } /* end */
9039};
9040
9041static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9042 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9043 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9044 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9045 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9046 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9047 { } /* end */
9048};
9049
Kailang Yang189609a2007-08-20 11:31:23 +02009050static struct hda_verb alc883_haier_w66_verbs[] = {
9051 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9052 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9053
9054 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9055
9056 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9057 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9058 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9059 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9060 { } /* end */
9061};
9062
Kailang Yange2757d52008-08-26 13:17:46 +02009063static struct hda_verb alc888_lenovo_sky_verbs[] = {
9064 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9065 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9066 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9067 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9068 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9069 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9070 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9071 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9072 { } /* end */
9073};
9074
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009075static struct hda_verb alc888_6st_dell_verbs[] = {
9076 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9077 { }
9078};
9079
Guido Günther3e1647c2009-06-05 00:47:26 +02009080static struct hda_verb alc883_vaiott_verbs[] = {
9081 /* HP */
9082 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9083 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9084
9085 /* enable unsolicited event */
9086 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9087
9088 { } /* end */
9089};
9090
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009091static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009092{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009093 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009094
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009095 spec->autocfg.hp_pins[0] = 0x1b;
9096 spec->autocfg.speaker_pins[0] = 0x14;
9097 spec->autocfg.speaker_pins[1] = 0x16;
9098 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009099}
9100
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009101static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009102 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009103 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9104 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009105 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009106 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009107};
9108
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009109/*
9110 * 2ch mode
9111 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009112static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009113 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9114 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9115 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9116 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009117 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009118};
9119
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009120/*
9121 * 4ch mode
9122 */
9123static struct hda_verb alc888_3st_hp_4ch_init[] = {
9124 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9125 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9126 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9127 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9128 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9129 { } /* end */
9130};
9131
9132/*
9133 * 6ch mode
9134 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009135static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009136 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9137 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009138 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009139 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9140 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009141 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9142 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009143};
9144
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009145static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009146 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009147 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009148 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009149};
9150
Kailang Yang272a5272007-05-14 11:00:38 +02009151/* toggle front-jack and RCA according to the hp-jack state */
9152static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9153{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009154 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009155
Takashi Iwai47fd8302007-08-10 17:11:07 +02009156 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9157 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9158 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9159 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009160}
9161
9162/* toggle RCA according to the front-jack state */
9163static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9164{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009165 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009166
Takashi Iwai47fd8302007-08-10 17:11:07 +02009167 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9168 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009169}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009170
Kailang Yang272a5272007-05-14 11:00:38 +02009171static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9172 unsigned int res)
9173{
9174 if ((res >> 26) == ALC880_HP_EVENT)
9175 alc888_lenovo_ms7195_front_automute(codec);
9176 if ((res >> 26) == ALC880_FRONT_EVENT)
9177 alc888_lenovo_ms7195_rca_automute(codec);
9178}
9179
9180static struct hda_verb alc883_medion_md2_verbs[] = {
9181 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9182 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9183
9184 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9185
9186 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9187 { } /* end */
9188};
9189
9190/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009191static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009192{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009193 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009194
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009195 spec->autocfg.hp_pins[0] = 0x14;
9196 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009197}
9198
Kailang Yangccc656c2006-10-17 12:32:26 +02009199/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009200#define alc883_targa_init_hook alc882_targa_init_hook
9201#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009202
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009203static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
9204{
9205 unsigned int present;
9206
Takashi Iwaid56757a2009-11-18 08:00:14 +01009207 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009208 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
9209 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9210}
9211
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009212static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009213{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009214 struct alc_spec *spec = codec->spec;
9215
9216 spec->autocfg.hp_pins[0] = 0x15;
9217 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009218}
9219
9220static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9221{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009222 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009223 alc883_clevo_m720_mic_automute(codec);
9224}
9225
9226static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009227 unsigned int res)
9228{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009229 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009230 case ALC880_MIC_EVENT:
9231 alc883_clevo_m720_mic_automute(codec);
9232 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009233 default:
9234 alc_automute_amp_unsol_event(codec, res);
9235 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009236 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009237}
9238
Jiang zhefb97dc62008-03-06 11:07:11 +01009239/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009240static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009241{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009242 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009243
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009244 spec->autocfg.hp_pins[0] = 0x14;
9245 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009246}
9247
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009248static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009249{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009250 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009251
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009252 spec->autocfg.hp_pins[0] = 0x1b;
9253 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009254}
9255
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009256static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9257{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009258 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009259
Takashi Iwai47fd8302007-08-10 17:11:07 +02009260 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9261 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009262}
9263
9264static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9265{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009266 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009267
Takashi Iwai47fd8302007-08-10 17:11:07 +02009268 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9269 HDA_AMP_MUTE, bits);
9270 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9271 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009272}
9273
9274static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9275 unsigned int res)
9276{
9277 if ((res >> 26) == ALC880_HP_EVENT)
9278 alc883_lenovo_101e_all_automute(codec);
9279 if ((res >> 26) == ALC880_FRONT_EVENT)
9280 alc883_lenovo_101e_ispeaker_automute(codec);
9281}
9282
Takashi Iwai676a9b52007-08-16 15:23:35 +02009283/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009284static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009285{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009286 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009287
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009288 spec->autocfg.hp_pins[0] = 0x14;
9289 spec->autocfg.speaker_pins[0] = 0x15;
9290 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009291}
9292
Kailang Yangd1a991a2007-08-15 16:21:59 +02009293static struct hda_verb alc883_acer_eapd_verbs[] = {
9294 /* HP Pin: output 0 (0x0c) */
9295 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9296 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9297 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9298 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009299 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9300 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009301 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009302 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9303 /* eanable EAPD on medion laptop */
9304 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9305 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009306 /* enable unsolicited event */
9307 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009308 { }
9309};
9310
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009311static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
9312 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9313 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9314 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9315 { } /* end */
9316};
9317
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009318static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009319{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009320 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009321
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009322 spec->autocfg.hp_pins[0] = 0x1b;
9323 spec->autocfg.speaker_pins[0] = 0x14;
9324 spec->autocfg.speaker_pins[1] = 0x15;
9325 spec->autocfg.speaker_pins[2] = 0x16;
9326 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009327}
9328
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009329static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009330{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009331 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009332
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009333 spec->autocfg.hp_pins[0] = 0x1b;
9334 spec->autocfg.speaker_pins[0] = 0x14;
9335 spec->autocfg.speaker_pins[1] = 0x15;
9336 spec->autocfg.speaker_pins[2] = 0x16;
9337 spec->autocfg.speaker_pins[3] = 0x17;
9338 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009339}
9340
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009341static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009342{
9343 struct alc_spec *spec = codec->spec;
9344
9345 spec->autocfg.hp_pins[0] = 0x15;
9346 spec->autocfg.speaker_pins[0] = 0x14;
9347 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009348}
9349
Kailang Yange2757d52008-08-26 13:17:46 +02009350static struct hda_verb alc888_asus_m90v_verbs[] = {
9351 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9352 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9353 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9354 /* enable unsolicited event */
9355 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9356 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9357 { } /* end */
9358};
9359
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009360static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009361{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009362 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009363
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009364 spec->autocfg.hp_pins[0] = 0x1b;
9365 spec->autocfg.speaker_pins[0] = 0x14;
9366 spec->autocfg.speaker_pins[1] = 0x15;
9367 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009368 spec->ext_mic.pin = 0x18;
9369 spec->int_mic.pin = 0x19;
9370 spec->ext_mic.mux_idx = 0;
9371 spec->int_mic.mux_idx = 1;
9372 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009373}
9374
9375static struct hda_verb alc888_asus_eee1601_verbs[] = {
9376 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9377 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9378 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9379 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9381 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9382 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9383 /* enable unsolicited event */
9384 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9385 { } /* end */
9386};
9387
Kailang Yange2757d52008-08-26 13:17:46 +02009388static void alc883_eee1601_inithook(struct hda_codec *codec)
9389{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009390 struct alc_spec *spec = codec->spec;
9391
9392 spec->autocfg.hp_pins[0] = 0x14;
9393 spec->autocfg.speaker_pins[0] = 0x1b;
9394 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009395}
9396
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009397static struct hda_verb alc889A_mb31_verbs[] = {
9398 /* Init rear pin (used as headphone output) */
9399 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9400 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9401 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9402 /* Init line pin (used as output in 4ch and 6ch mode) */
9403 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9404 /* Init line 2 pin (used as headphone out by default) */
9405 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9406 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9407 { } /* end */
9408};
9409
9410/* Mute speakers according to the headphone jack state */
9411static void alc889A_mb31_automute(struct hda_codec *codec)
9412{
9413 unsigned int present;
9414
9415 /* Mute only in 2ch or 4ch mode */
9416 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9417 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009418 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009419 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9420 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9421 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9422 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9423 }
9424}
9425
9426static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9427{
9428 if ((res >> 26) == ALC880_HP_EVENT)
9429 alc889A_mb31_automute(codec);
9430}
9431
Takashi Iwai49535502009-06-30 15:28:30 +02009432
Takashi Iwaicb53c622007-08-10 17:21:45 +02009433#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009434#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009435#endif
9436
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009437/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +02009438#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9439#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9440#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9441#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9442
9443static hda_nid_t alc883_slave_dig_outs[] = {
9444 ALC1200_DIGOUT_NID, 0,
9445};
9446
9447static hda_nid_t alc1200_slave_dig_outs[] = {
9448 ALC883_DIGOUT_NID, 0,
9449};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009450
9451/*
9452 * configuration and preset
9453 */
Takashi Iwai49535502009-06-30 15:28:30 +02009454static const char *alc882_models[ALC882_MODEL_LAST] = {
9455 [ALC882_3ST_DIG] = "3stack-dig",
9456 [ALC882_6ST_DIG] = "6stack-dig",
9457 [ALC882_ARIMA] = "arima",
9458 [ALC882_W2JC] = "w2jc",
9459 [ALC882_TARGA] = "targa",
9460 [ALC882_ASUS_A7J] = "asus-a7j",
9461 [ALC882_ASUS_A7M] = "asus-a7m",
9462 [ALC885_MACPRO] = "macpro",
9463 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009464 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009465 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009466 [ALC885_MBP3] = "mbp3",
9467 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009468 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009469 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009470 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9471 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009472 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009473 [ALC883_TARGA_DIG] = "targa-dig",
9474 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009475 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009476 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009477 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009478 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009479 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009480 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009481 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009482 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009483 [ALC883_MEDION_MD2] = "medion-md2",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009484 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009485 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009486 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009487 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9488 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009489 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009490 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009491 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009492 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009493 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309494 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009495 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009496 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009497 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009498 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009499 [ALC889A_INTEL] = "intel-alc889a",
9500 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009501 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009502 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009503 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009504 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009505};
9506
Takashi Iwai49535502009-06-30 15:28:30 +02009507static struct snd_pci_quirk alc882_cfg_tbl[] = {
9508 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9509
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009510 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009511 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009512 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009513 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9514 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009515 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009516 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9517 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009518 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009519 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009520 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9521 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009522 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9523 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009524 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9525 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009526 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009527 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009528 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009529 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009530 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9531 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009532 /* default Acer -- disabled as it causes more problems.
9533 * model=auto should work fine now
9534 */
9535 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009536
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009537 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009538
Tobin Davisfebe3372007-06-12 11:27:46 +02009539 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009540 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9541 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009542 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009543 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009544 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009545
9546 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9547 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9548 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009549 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009550 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9551 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9552 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009553 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009554 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009555 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009556 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009557
9558 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009559 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009560 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009561 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009562 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9563 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009564 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009565 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009566 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9567
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009568 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9569 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9570 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009571 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009572 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009573 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009574 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009575 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009576 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9577 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9578 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9579 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9580 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9581 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009582 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009583 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9584 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9585 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009586 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009587 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009588 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9589 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009590 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009591 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009592 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009593 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009594 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009595 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009596 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009597 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009598 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009599
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009600 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009601 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009602 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9603 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309604 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009605 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009606 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009607 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009608 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009609 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009610 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009611 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009612 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009613 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009614 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009615 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9616 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009617 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009618 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009619 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009620 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009621 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009622
Jiang zhe17bba1b2008-06-04 12:11:07 +02009623 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9624 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009625 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009626 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9627 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9628 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009629 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009630
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009631 {}
9632};
9633
Takashi Iwai49535502009-06-30 15:28:30 +02009634/* codec SSID table for Intel Mac */
9635static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9636 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9637 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9638 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9639 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9640 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9641 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9642 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009643 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009644 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009645 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009646 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +02009647 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9648 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9649 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009650 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009651 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009652 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009653 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9654 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009655 */
9656 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009657 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009658 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +02009659 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009660};
9661
Takashi Iwai49535502009-06-30 15:28:30 +02009662static struct alc_config_preset alc882_presets[] = {
9663 [ALC882_3ST_DIG] = {
9664 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009665 .init_verbs = { alc882_base_init_verbs,
9666 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009667 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9668 .dac_nids = alc882_dac_nids,
9669 .dig_out_nid = ALC882_DIGOUT_NID,
9670 .dig_in_nid = ALC882_DIGIN_NID,
9671 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9672 .channel_mode = alc882_ch_modes,
9673 .need_dac_fix = 1,
9674 .input_mux = &alc882_capture_source,
9675 },
9676 [ALC882_6ST_DIG] = {
9677 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009678 .init_verbs = { alc882_base_init_verbs,
9679 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009680 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9681 .dac_nids = alc882_dac_nids,
9682 .dig_out_nid = ALC882_DIGOUT_NID,
9683 .dig_in_nid = ALC882_DIGIN_NID,
9684 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9685 .channel_mode = alc882_sixstack_modes,
9686 .input_mux = &alc882_capture_source,
9687 },
9688 [ALC882_ARIMA] = {
9689 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009690 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9691 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009692 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9693 .dac_nids = alc882_dac_nids,
9694 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9695 .channel_mode = alc882_sixstack_modes,
9696 .input_mux = &alc882_capture_source,
9697 },
9698 [ALC882_W2JC] = {
9699 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009700 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9701 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009702 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9703 .dac_nids = alc882_dac_nids,
9704 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9705 .channel_mode = alc880_threestack_modes,
9706 .need_dac_fix = 1,
9707 .input_mux = &alc882_capture_source,
9708 .dig_out_nid = ALC882_DIGOUT_NID,
9709 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009710 [ALC885_MBA21] = {
9711 .mixers = { alc885_mba21_mixer },
9712 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9713 .num_dacs = 2,
9714 .dac_nids = alc882_dac_nids,
9715 .channel_mode = alc885_mba21_ch_modes,
9716 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9717 .input_mux = &alc882_capture_source,
9718 .unsol_event = alc_automute_amp_unsol_event,
9719 .setup = alc885_mba21_setup,
9720 .init_hook = alc_automute_amp,
9721 },
Takashi Iwai49535502009-06-30 15:28:30 +02009722 [ALC885_MBP3] = {
9723 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9724 .init_verbs = { alc885_mbp3_init_verbs,
9725 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009726 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +02009727 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009728 .hp_nid = 0x04,
9729 .channel_mode = alc885_mbp_4ch_modes,
9730 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +02009731 .input_mux = &alc882_capture_source,
9732 .dig_out_nid = ALC882_DIGOUT_NID,
9733 .dig_in_nid = ALC882_DIGIN_NID,
9734 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009735 .setup = alc885_mbp3_setup,
9736 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009737 },
9738 [ALC885_MB5] = {
9739 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9740 .init_verbs = { alc885_mb5_init_verbs,
9741 alc880_gpio1_init_verbs },
9742 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9743 .dac_nids = alc882_dac_nids,
9744 .channel_mode = alc885_mb5_6ch_modes,
9745 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9746 .input_mux = &mb5_capture_source,
9747 .dig_out_nid = ALC882_DIGOUT_NID,
9748 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009749 .unsol_event = alc_automute_amp_unsol_event,
9750 .setup = alc885_mb5_setup,
9751 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009752 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009753 [ALC885_MACMINI3] = {
9754 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9755 .init_verbs = { alc885_macmini3_init_verbs,
9756 alc880_gpio1_init_verbs },
9757 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9758 .dac_nids = alc882_dac_nids,
9759 .channel_mode = alc885_macmini3_6ch_modes,
9760 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9761 .input_mux = &macmini3_capture_source,
9762 .dig_out_nid = ALC882_DIGOUT_NID,
9763 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009764 .unsol_event = alc_automute_amp_unsol_event,
9765 .setup = alc885_macmini3_setup,
9766 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009767 },
Takashi Iwai49535502009-06-30 15:28:30 +02009768 [ALC885_MACPRO] = {
9769 .mixers = { alc882_macpro_mixer },
9770 .init_verbs = { alc882_macpro_init_verbs },
9771 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9772 .dac_nids = alc882_dac_nids,
9773 .dig_out_nid = ALC882_DIGOUT_NID,
9774 .dig_in_nid = ALC882_DIGIN_NID,
9775 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9776 .channel_mode = alc882_ch_modes,
9777 .input_mux = &alc882_capture_source,
9778 .init_hook = alc885_macpro_init_hook,
9779 },
9780 [ALC885_IMAC24] = {
9781 .mixers = { alc885_imac24_mixer },
9782 .init_verbs = { alc885_imac24_init_verbs },
9783 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9784 .dac_nids = alc882_dac_nids,
9785 .dig_out_nid = ALC882_DIGOUT_NID,
9786 .dig_in_nid = ALC882_DIGIN_NID,
9787 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9788 .channel_mode = alc882_ch_modes,
9789 .input_mux = &alc882_capture_source,
9790 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009791 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +02009792 .init_hook = alc885_imac24_init_hook,
9793 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009794 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009795 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009796 .init_verbs = { alc885_imac91_init_verbs,
9797 alc880_gpio1_init_verbs },
9798 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9799 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009800 .channel_mode = alc885_mba21_ch_modes,
9801 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9802 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009803 .dig_out_nid = ALC882_DIGOUT_NID,
9804 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009805 .unsol_event = alc_automute_amp_unsol_event,
9806 .setup = alc885_imac91_setup,
9807 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009808 },
Takashi Iwai49535502009-06-30 15:28:30 +02009809 [ALC882_TARGA] = {
9810 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009811 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009812 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009813 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9814 .dac_nids = alc882_dac_nids,
9815 .dig_out_nid = ALC882_DIGOUT_NID,
9816 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9817 .adc_nids = alc882_adc_nids,
9818 .capsrc_nids = alc882_capsrc_nids,
9819 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9820 .channel_mode = alc882_3ST_6ch_modes,
9821 .need_dac_fix = 1,
9822 .input_mux = &alc882_capture_source,
9823 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009824 .setup = alc882_targa_setup,
9825 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +02009826 },
9827 [ALC882_ASUS_A7J] = {
9828 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009829 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9830 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +02009831 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9832 .dac_nids = alc882_dac_nids,
9833 .dig_out_nid = ALC882_DIGOUT_NID,
9834 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9835 .adc_nids = alc882_adc_nids,
9836 .capsrc_nids = alc882_capsrc_nids,
9837 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9838 .channel_mode = alc882_3ST_6ch_modes,
9839 .need_dac_fix = 1,
9840 .input_mux = &alc882_capture_source,
9841 },
9842 [ALC882_ASUS_A7M] = {
9843 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009844 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9845 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +02009846 alc882_asus_a7m_verbs },
9847 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9848 .dac_nids = alc882_dac_nids,
9849 .dig_out_nid = ALC882_DIGOUT_NID,
9850 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9851 .channel_mode = alc880_threestack_modes,
9852 .need_dac_fix = 1,
9853 .input_mux = &alc882_capture_source,
9854 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009855 [ALC883_3ST_2ch_DIG] = {
9856 .mixers = { alc883_3ST_2ch_mixer },
9857 .init_verbs = { alc883_init_verbs },
9858 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9859 .dac_nids = alc883_dac_nids,
9860 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009861 .dig_in_nid = ALC883_DIGIN_NID,
9862 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9863 .channel_mode = alc883_3ST_2ch_modes,
9864 .input_mux = &alc883_capture_source,
9865 },
9866 [ALC883_3ST_6ch_DIG] = {
9867 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9868 .init_verbs = { alc883_init_verbs },
9869 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9870 .dac_nids = alc883_dac_nids,
9871 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009872 .dig_in_nid = ALC883_DIGIN_NID,
9873 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9874 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009875 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009876 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009877 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009878 [ALC883_3ST_6ch] = {
9879 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9880 .init_verbs = { alc883_init_verbs },
9881 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9882 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009883 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9884 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009885 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009886 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009887 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009888 [ALC883_3ST_6ch_INTEL] = {
9889 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9890 .init_verbs = { alc883_init_verbs },
9891 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9892 .dac_nids = alc883_dac_nids,
9893 .dig_out_nid = ALC883_DIGOUT_NID,
9894 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009895 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009896 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9897 .channel_mode = alc883_3ST_6ch_intel_modes,
9898 .need_dac_fix = 1,
9899 .input_mux = &alc883_3stack_6ch_intel,
9900 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009901 [ALC889A_INTEL] = {
9902 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009903 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9904 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009905 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9906 .dac_nids = alc883_dac_nids,
9907 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9908 .adc_nids = alc889_adc_nids,
9909 .dig_out_nid = ALC883_DIGOUT_NID,
9910 .dig_in_nid = ALC883_DIGIN_NID,
9911 .slave_dig_outs = alc883_slave_dig_outs,
9912 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9913 .channel_mode = alc889_8ch_intel_modes,
9914 .capsrc_nids = alc889_capsrc_nids,
9915 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009916 .setup = alc889_automute_setup,
9917 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009918 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009919 .need_dac_fix = 1,
9920 },
9921 [ALC889_INTEL] = {
9922 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9923 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009924 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009925 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9926 .dac_nids = alc883_dac_nids,
9927 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9928 .adc_nids = alc889_adc_nids,
9929 .dig_out_nid = ALC883_DIGOUT_NID,
9930 .dig_in_nid = ALC883_DIGIN_NID,
9931 .slave_dig_outs = alc883_slave_dig_outs,
9932 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9933 .channel_mode = alc889_8ch_intel_modes,
9934 .capsrc_nids = alc889_capsrc_nids,
9935 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009936 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009937 .init_hook = alc889_intel_init_hook,
9938 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009939 .need_dac_fix = 1,
9940 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009941 [ALC883_6ST_DIG] = {
9942 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9943 .init_verbs = { alc883_init_verbs },
9944 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9945 .dac_nids = alc883_dac_nids,
9946 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009947 .dig_in_nid = ALC883_DIGIN_NID,
9948 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9949 .channel_mode = alc883_sixstack_modes,
9950 .input_mux = &alc883_capture_source,
9951 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009952 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009953 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009954 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9955 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009956 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9957 .dac_nids = alc883_dac_nids,
9958 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009959 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9960 .channel_mode = alc883_3ST_6ch_modes,
9961 .need_dac_fix = 1,
9962 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009963 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009964 .setup = alc882_targa_setup,
9965 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009966 },
9967 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009968 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009969 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9970 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009971 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9972 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009973 .adc_nids = alc883_adc_nids_alt,
9974 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009975 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +02009976 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009977 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9978 .channel_mode = alc883_3ST_2ch_modes,
9979 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009980 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009981 .setup = alc882_targa_setup,
9982 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009983 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009984 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009985 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9986 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009987 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009988 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009989 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9990 .dac_nids = alc883_dac_nids,
9991 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9992 .adc_nids = alc883_adc_nids_rev,
9993 .capsrc_nids = alc883_capsrc_nids_rev,
9994 .dig_out_nid = ALC883_DIGOUT_NID,
9995 .dig_in_nid = ALC883_DIGIN_NID,
9996 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
9997 .channel_mode = alc883_4ST_8ch_modes,
9998 .need_dac_fix = 1,
9999 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010000 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010001 .setup = alc882_targa_setup,
10002 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010003 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010004 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010005 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010006 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10007 * and the headphone jack. Turn this on and rely on the
10008 * standard mute methods whenever the user wants to turn
10009 * these outputs off.
10010 */
10011 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10012 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10013 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010014 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10015 .channel_mode = alc883_3ST_2ch_modes,
10016 .input_mux = &alc883_capture_source,
10017 },
Tobin Davis2880a862007-08-07 11:50:26 +020010018 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010019 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010020 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010021 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10022 .dac_nids = alc883_dac_nids,
10023 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010024 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10025 .channel_mode = alc883_3ST_2ch_modes,
10026 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010027 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010028 .setup = alc883_acer_aspire_setup,
10029 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010030 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010031 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010032 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010033 alc883_chmode_mixer },
10034 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10035 alc888_acer_aspire_4930g_verbs },
10036 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10037 .dac_nids = alc883_dac_nids,
10038 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10039 .adc_nids = alc883_adc_nids_rev,
10040 .capsrc_nids = alc883_capsrc_nids_rev,
10041 .dig_out_nid = ALC883_DIGOUT_NID,
10042 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10043 .channel_mode = alc883_3ST_6ch_modes,
10044 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010045 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010046 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010047 ARRAY_SIZE(alc888_2_capture_sources),
10048 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010049 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010050 .setup = alc888_acer_aspire_4930g_setup,
10051 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010052 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010053 [ALC888_ACER_ASPIRE_6530G] = {
10054 .mixers = { alc888_acer_aspire_6530_mixer },
10055 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10056 alc888_acer_aspire_6530g_verbs },
10057 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10058 .dac_nids = alc883_dac_nids,
10059 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10060 .adc_nids = alc883_adc_nids_rev,
10061 .capsrc_nids = alc883_capsrc_nids_rev,
10062 .dig_out_nid = ALC883_DIGOUT_NID,
10063 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10064 .channel_mode = alc883_3ST_2ch_modes,
10065 .num_mux_defs =
10066 ARRAY_SIZE(alc888_2_capture_sources),
10067 .input_mux = alc888_acer_aspire_6530_sources,
10068 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010069 .setup = alc888_acer_aspire_6530g_setup,
10070 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010071 },
Hector Martin3b315d72009-06-02 10:54:19 +020010072 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010073 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010074 alc883_chmode_mixer },
10075 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010076 alc889_acer_aspire_8930g_verbs,
10077 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010078 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10079 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010080 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10081 .adc_nids = alc889_adc_nids,
10082 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010083 .dig_out_nid = ALC883_DIGOUT_NID,
10084 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10085 .channel_mode = alc883_3ST_6ch_modes,
10086 .need_dac_fix = 1,
10087 .const_channel_count = 6,
10088 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010089 ARRAY_SIZE(alc889_capture_sources),
10090 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010091 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010092 .setup = alc889_acer_aspire_8930g_setup,
10093 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010094#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010095 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010096#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010097 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010098 [ALC888_ACER_ASPIRE_7730G] = {
10099 .mixers = { alc883_3ST_6ch_mixer,
10100 alc883_chmode_mixer },
10101 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10102 alc888_acer_aspire_7730G_verbs },
10103 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10104 .dac_nids = alc883_dac_nids,
10105 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10106 .adc_nids = alc883_adc_nids_rev,
10107 .capsrc_nids = alc883_capsrc_nids_rev,
10108 .dig_out_nid = ALC883_DIGOUT_NID,
10109 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10110 .channel_mode = alc883_3ST_6ch_modes,
10111 .need_dac_fix = 1,
10112 .const_channel_count = 6,
10113 .input_mux = &alc883_capture_source,
10114 .unsol_event = alc_automute_amp_unsol_event,
10115 .setup = alc888_acer_aspire_6530g_setup,
10116 .init_hook = alc_automute_amp,
10117 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010118 [ALC883_MEDION] = {
10119 .mixers = { alc883_fivestack_mixer,
10120 alc883_chmode_mixer },
10121 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010122 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010123 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10124 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010125 .adc_nids = alc883_adc_nids_alt,
10126 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010127 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010128 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10129 .channel_mode = alc883_sixstack_modes,
10130 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010131 },
Kailang Yang272a5272007-05-14 11:00:38 +020010132 [ALC883_MEDION_MD2] = {
10133 .mixers = { alc883_medion_md2_mixer},
10134 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
10135 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10136 .dac_nids = alc883_dac_nids,
10137 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010138 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10139 .channel_mode = alc883_3ST_2ch_modes,
10140 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010141 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010142 .setup = alc883_medion_md2_setup,
10143 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020010144 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010145 [ALC883_MEDION_WIM2160] = {
10146 .mixers = { alc883_medion_wim2160_mixer },
10147 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10148 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10149 .dac_nids = alc883_dac_nids,
10150 .dig_out_nid = ALC883_DIGOUT_NID,
10151 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10152 .adc_nids = alc883_adc_nids,
10153 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10154 .channel_mode = alc883_3ST_2ch_modes,
10155 .input_mux = &alc883_capture_source,
10156 .unsol_event = alc_automute_amp_unsol_event,
10157 .setup = alc883_medion_wim2160_setup,
10158 .init_hook = alc_automute_amp,
10159 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010160 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010161 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010162 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10163 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10164 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010165 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10166 .channel_mode = alc883_3ST_2ch_modes,
10167 .input_mux = &alc883_capture_source,
10168 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010169 [ALC883_CLEVO_M540R] = {
10170 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10171 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10172 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10173 .dac_nids = alc883_dac_nids,
10174 .dig_out_nid = ALC883_DIGOUT_NID,
10175 .dig_in_nid = ALC883_DIGIN_NID,
10176 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10177 .channel_mode = alc883_3ST_6ch_clevo_modes,
10178 .need_dac_fix = 1,
10179 .input_mux = &alc883_capture_source,
10180 /* This machine has the hardware HP auto-muting, thus
10181 * we need no software mute via unsol event
10182 */
10183 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010184 [ALC883_CLEVO_M720] = {
10185 .mixers = { alc883_clevo_m720_mixer },
10186 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010187 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10188 .dac_nids = alc883_dac_nids,
10189 .dig_out_nid = ALC883_DIGOUT_NID,
10190 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10191 .channel_mode = alc883_3ST_2ch_modes,
10192 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010193 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010194 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010195 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010196 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010197 [ALC883_LENOVO_101E_2ch] = {
10198 .mixers = { alc883_lenovo_101e_2ch_mixer},
10199 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10200 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10201 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010202 .adc_nids = alc883_adc_nids_alt,
10203 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010204 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010205 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10206 .channel_mode = alc883_3ST_2ch_modes,
10207 .input_mux = &alc883_lenovo_101e_capture_source,
10208 .unsol_event = alc883_lenovo_101e_unsol_event,
10209 .init_hook = alc883_lenovo_101e_all_automute,
10210 },
Kailang Yang272a5272007-05-14 11:00:38 +020010211 [ALC883_LENOVO_NB0763] = {
10212 .mixers = { alc883_lenovo_nb0763_mixer },
10213 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10214 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10215 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010216 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10217 .channel_mode = alc883_3ST_2ch_modes,
10218 .need_dac_fix = 1,
10219 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010220 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010221 .setup = alc883_medion_md2_setup,
10222 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010223 },
10224 [ALC888_LENOVO_MS7195_DIG] = {
10225 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10226 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10227 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10228 .dac_nids = alc883_dac_nids,
10229 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010230 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10231 .channel_mode = alc883_3ST_6ch_modes,
10232 .need_dac_fix = 1,
10233 .input_mux = &alc883_capture_source,
10234 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10235 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010236 },
10237 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010238 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010239 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10240 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10241 .dac_nids = alc883_dac_nids,
10242 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010243 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10244 .channel_mode = alc883_3ST_2ch_modes,
10245 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010246 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010247 .setup = alc883_haier_w66_setup,
10248 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010249 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010250 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010251 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010252 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010253 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10254 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010255 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10256 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010257 .need_dac_fix = 1,
10258 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010259 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010260 .setup = alc888_3st_hp_setup,
10261 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010262 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010263 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010264 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010265 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10266 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10267 .dac_nids = alc883_dac_nids,
10268 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010269 .dig_in_nid = ALC883_DIGIN_NID,
10270 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10271 .channel_mode = alc883_sixstack_modes,
10272 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010273 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010274 .setup = alc888_6st_dell_setup,
10275 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010276 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010277 [ALC883_MITAC] = {
10278 .mixers = { alc883_mitac_mixer },
10279 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10280 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10281 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010282 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10283 .channel_mode = alc883_3ST_2ch_modes,
10284 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010285 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010286 .setup = alc883_mitac_setup,
10287 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010288 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010289 [ALC883_FUJITSU_PI2515] = {
10290 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10291 .init_verbs = { alc883_init_verbs,
10292 alc883_2ch_fujitsu_pi2515_verbs},
10293 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10294 .dac_nids = alc883_dac_nids,
10295 .dig_out_nid = ALC883_DIGOUT_NID,
10296 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10297 .channel_mode = alc883_3ST_2ch_modes,
10298 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010299 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010300 .setup = alc883_2ch_fujitsu_pi2515_setup,
10301 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010302 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010303 [ALC888_FUJITSU_XA3530] = {
10304 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10305 .init_verbs = { alc883_init_verbs,
10306 alc888_fujitsu_xa3530_verbs },
10307 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10308 .dac_nids = alc883_dac_nids,
10309 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10310 .adc_nids = alc883_adc_nids_rev,
10311 .capsrc_nids = alc883_capsrc_nids_rev,
10312 .dig_out_nid = ALC883_DIGOUT_NID,
10313 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10314 .channel_mode = alc888_4ST_8ch_intel_modes,
10315 .num_mux_defs =
10316 ARRAY_SIZE(alc888_2_capture_sources),
10317 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010318 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010319 .setup = alc888_fujitsu_xa3530_setup,
10320 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010321 },
Kailang Yange2757d52008-08-26 13:17:46 +020010322 [ALC888_LENOVO_SKY] = {
10323 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10324 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10325 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10326 .dac_nids = alc883_dac_nids,
10327 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010328 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10329 .channel_mode = alc883_sixstack_modes,
10330 .need_dac_fix = 1,
10331 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010332 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010333 .setup = alc888_lenovo_sky_setup,
10334 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010335 },
10336 [ALC888_ASUS_M90V] = {
10337 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10338 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10339 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10340 .dac_nids = alc883_dac_nids,
10341 .dig_out_nid = ALC883_DIGOUT_NID,
10342 .dig_in_nid = ALC883_DIGIN_NID,
10343 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10344 .channel_mode = alc883_3ST_6ch_modes,
10345 .need_dac_fix = 1,
10346 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010347 .unsol_event = alc_sku_unsol_event,
10348 .setup = alc883_mode2_setup,
10349 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010350 },
10351 [ALC888_ASUS_EEE1601] = {
10352 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010353 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010354 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10355 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10356 .dac_nids = alc883_dac_nids,
10357 .dig_out_nid = ALC883_DIGOUT_NID,
10358 .dig_in_nid = ALC883_DIGIN_NID,
10359 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10360 .channel_mode = alc883_3ST_2ch_modes,
10361 .need_dac_fix = 1,
10362 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010363 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010364 .init_hook = alc883_eee1601_inithook,
10365 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010366 [ALC1200_ASUS_P5Q] = {
10367 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10368 .init_verbs = { alc883_init_verbs },
10369 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10370 .dac_nids = alc883_dac_nids,
10371 .dig_out_nid = ALC1200_DIGOUT_NID,
10372 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010373 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010374 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10375 .channel_mode = alc883_sixstack_modes,
10376 .input_mux = &alc883_capture_source,
10377 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010378 [ALC889A_MB31] = {
10379 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10380 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10381 alc880_gpio1_init_verbs },
10382 .adc_nids = alc883_adc_nids,
10383 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010384 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010385 .dac_nids = alc883_dac_nids,
10386 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10387 .channel_mode = alc889A_mb31_6ch_modes,
10388 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10389 .input_mux = &alc889A_mb31_capture_source,
10390 .dig_out_nid = ALC883_DIGOUT_NID,
10391 .unsol_event = alc889A_mb31_unsol_event,
10392 .init_hook = alc889A_mb31_automute,
10393 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010394 [ALC883_SONY_VAIO_TT] = {
10395 .mixers = { alc883_vaiott_mixer },
10396 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10397 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10398 .dac_nids = alc883_dac_nids,
10399 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10400 .channel_mode = alc883_3ST_2ch_modes,
10401 .input_mux = &alc883_capture_source,
10402 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010403 .setup = alc883_vaiott_setup,
10404 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010405 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010406};
10407
10408
10409/*
Takashi Iwai49535502009-06-30 15:28:30 +020010410 * Pin config fixes
10411 */
10412enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010413 PINFIX_ABIT_AW9D_MAX,
10414 PINFIX_PB_M5210,
Takashi Iwai49535502009-06-30 15:28:30 +020010415};
10416
10417static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
10418 { 0x15, 0x01080104 }, /* side */
10419 { 0x16, 0x01011012 }, /* rear */
10420 { 0x17, 0x01016011 }, /* clfe */
10421 { }
10422};
10423
Takashi Iwai954a29c2010-07-30 10:55:44 +020010424static const struct hda_verb pb_m5210_verbs[] = {
10425 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10426 {}
10427};
10428
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010429static const struct alc_fixup alc882_fixups[] = {
10430 [PINFIX_ABIT_AW9D_MAX] = {
10431 .pins = alc882_abit_aw9d_pinfix
10432 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010433 [PINFIX_PB_M5210] = {
10434 .verbs = pb_m5210_verbs
10435 },
Takashi Iwai49535502009-06-30 15:28:30 +020010436};
10437
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010438static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010439 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai49535502009-06-30 15:28:30 +020010440 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
10441 {}
10442};
10443
10444/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010445 * BIOS auto configuration
10446 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010447static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10448 const struct auto_pin_cfg *cfg)
10449{
10450 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10451}
10452
Takashi Iwai49535502009-06-30 15:28:30 +020010453static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010454 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010455 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010456{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010457 int idx;
10458
Takashi Iwai489008c2010-04-07 09:06:00 +020010459 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010460 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010461
Takashi Iwai489008c2010-04-07 09:06:00 +020010462 if (dac == 0x25)
10463 idx = 4;
10464 else if (dac >= 0x02 && dac <= 0x05)
10465 idx = dac - 2;
10466 else
10467 return;
10468 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010469}
10470
Takashi Iwai49535502009-06-30 15:28:30 +020010471static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010472{
10473 struct alc_spec *spec = codec->spec;
10474 int i;
10475
10476 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010477 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010478 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010479 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020010480 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010481 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010482 }
10483}
10484
Takashi Iwai49535502009-06-30 15:28:30 +020010485static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010486{
10487 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010488 hda_nid_t pin, dac;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010489
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010490 pin = spec->autocfg.hp_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010491 if (pin) {
10492 dac = spec->multiout.hp_nid;
10493 if (!dac)
10494 dac = spec->multiout.dac_nids[0]; /* to front */
10495 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10496 }
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010497 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010498 if (pin) {
10499 dac = spec->multiout.extra_out_nid[0];
10500 if (!dac)
10501 dac = spec->multiout.dac_nids[0]; /* to front */
10502 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10503 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010504}
10505
Takashi Iwai49535502009-06-30 15:28:30 +020010506static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010507{
10508 struct alc_spec *spec = codec->spec;
10509 int i;
10510
10511 for (i = 0; i < AUTO_PIN_LAST; i++) {
10512 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai49535502009-06-30 15:28:30 +020010513 if (!nid)
10514 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +020010515 alc_set_input_pin(codec, nid, i);
Takashi Iwai49535502009-06-30 15:28:30 +020010516 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10517 snd_hda_codec_write(codec, nid, 0,
10518 AC_VERB_SET_AMP_GAIN_MUTE,
10519 AMP_OUT_MUTE);
10520 }
10521}
10522
10523static void alc882_auto_init_input_src(struct hda_codec *codec)
10524{
10525 struct alc_spec *spec = codec->spec;
10526 int c;
10527
10528 for (c = 0; c < spec->num_adc_nids; c++) {
10529 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10530 hda_nid_t nid = spec->capsrc_nids[c];
10531 unsigned int mux_idx;
10532 const struct hda_input_mux *imux;
10533 int conns, mute, idx, item;
10534
10535 conns = snd_hda_get_connections(codec, nid, conn_list,
10536 ARRAY_SIZE(conn_list));
10537 if (conns < 0)
10538 continue;
10539 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10540 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010541 if (!imux->num_items && mux_idx > 0)
10542 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020010543 for (idx = 0; idx < conns; idx++) {
10544 /* if the current connection is the selected one,
10545 * unmute it as default - otherwise mute it
10546 */
10547 mute = AMP_IN_MUTE(idx);
10548 for (item = 0; item < imux->num_items; item++) {
10549 if (imux->items[item].index == idx) {
10550 if (spec->cur_mux[c] == item)
10551 mute = AMP_IN_UNMUTE(idx);
10552 break;
10553 }
10554 }
10555 /* check if we have a selector or mixer
10556 * we could check for the widget type instead, but
10557 * just check for Amp-In presence (in case of mixer
10558 * without amp-in there is something wrong, this
10559 * function shouldn't be used or capsrc nid is wrong)
10560 */
10561 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010562 snd_hda_codec_write(codec, nid, 0,
10563 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020010564 mute);
10565 else if (mute != AMP_IN_MUTE(idx))
10566 snd_hda_codec_write(codec, nid, 0,
10567 AC_VERB_SET_CONNECT_SEL,
10568 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010569 }
10570 }
10571}
10572
Takashi Iwai49535502009-06-30 15:28:30 +020010573/* add mic boosts if needed */
10574static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010575{
10576 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010577 int err;
10578 hda_nid_t nid;
10579
10580 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
10581 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10582 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10583 "Mic Boost",
10584 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10585 if (err < 0)
10586 return err;
10587 }
10588 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
10589 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10590 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10591 "Front Mic Boost",
10592 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10593 if (err < 0)
10594 return err;
10595 }
10596 return 0;
10597}
10598
10599/* almost identical with ALC880 parser... */
10600static int alc882_parse_auto_config(struct hda_codec *codec)
10601{
10602 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010603 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010604 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010605
Takashi Iwai05f5f472009-08-25 13:10:18 +020010606 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10607 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010608 if (err < 0)
10609 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010610 if (!spec->autocfg.line_outs)
10611 return 0; /* can't find valid BIOS pin config */
10612
10613 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10614 if (err < 0)
10615 return err;
10616 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10617 if (err < 0)
10618 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010619 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10620 "Headphone");
10621 if (err < 0)
10622 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010623 err = alc880_auto_create_extra_out(spec,
10624 spec->autocfg.speaker_pins[0],
10625 "Speaker");
10626 if (err < 0)
10627 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010628 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10629 if (err < 0)
10630 return err;
10631
10632 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10633
Takashi Iwai757899a2010-07-30 10:48:14 +020010634 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010635
10636 if (spec->kctls.list)
10637 add_mixer(spec, spec->kctls.list);
10638
10639 add_verb(spec, alc883_auto_init_verbs);
10640 /* if ADC 0x07 is available, initialize it, too */
10641 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10642 add_verb(spec, alc882_adc1_init_verbs);
10643
10644 spec->num_mux_defs = 1;
10645 spec->input_mux = &spec->private_imux[0];
10646
Kailang Yang6227cdc2010-02-25 08:36:52 +010010647 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010648
10649 err = alc_auto_add_mic_boost(codec);
10650 if (err < 0)
10651 return err;
10652
Takashi Iwai776e1842007-08-29 15:07:11 +020010653 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010654}
10655
10656/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010657static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010658{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010659 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010660 alc882_auto_init_multi_out(codec);
10661 alc882_auto_init_hp_out(codec);
10662 alc882_auto_init_analog_input(codec);
10663 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010664 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010665 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010666 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010667}
10668
Takashi Iwai49535502009-06-30 15:28:30 +020010669static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010670{
10671 struct alc_spec *spec;
10672 int err, board_config;
10673
10674 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10675 if (spec == NULL)
10676 return -ENOMEM;
10677
10678 codec->spec = spec;
10679
Kailang Yangda00c242010-03-19 11:23:45 +010010680 alc_auto_parse_customize_define(codec);
10681
Takashi Iwai49535502009-06-30 15:28:30 +020010682 switch (codec->vendor_id) {
10683 case 0x10ec0882:
10684 case 0x10ec0885:
10685 break;
10686 default:
10687 /* ALC883 and variants */
10688 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10689 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010690 }
10691
Takashi Iwai49535502009-06-30 15:28:30 +020010692 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10693 alc882_models,
10694 alc882_cfg_tbl);
10695
10696 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10697 board_config = snd_hda_check_board_codec_sid_config(codec,
10698 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10699
10700 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010701 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010702 codec->chip_name);
10703 board_config = ALC882_AUTO;
10704 }
10705
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010706 if (board_config == ALC882_AUTO)
10707 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai49535502009-06-30 15:28:30 +020010708
10709 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010710 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020010711 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010712 if (err < 0) {
10713 alc_free(codec);
10714 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010715 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010716 printk(KERN_INFO
10717 "hda_codec: Cannot set up configuration "
10718 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020010719 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010720 }
10721 }
10722
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010723 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020010724 err = snd_hda_attach_beep_device(codec, 0x1);
10725 if (err < 0) {
10726 alc_free(codec);
10727 return err;
10728 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010729 }
10730
Takashi Iwai49535502009-06-30 15:28:30 +020010731 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010732 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010733
Takashi Iwai49535502009-06-30 15:28:30 +020010734 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10735 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10736 /* FIXME: setup DAC5 */
10737 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10738 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10739
10740 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10741 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10742
Takashi Iwai49535502009-06-30 15:28:30 +020010743 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010744 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020010745 spec->num_adc_nids = 0;
10746 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010747 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020010748 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010749 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020010750 hda_nid_t nid = alc882_adc_nids[i];
10751 unsigned int wcap = get_wcaps(codec, nid);
10752 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010753 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020010754 if (wcap != AC_WID_AUD_IN)
10755 continue;
10756 spec->private_adc_nids[spec->num_adc_nids] = nid;
10757 err = snd_hda_get_connections(codec, nid, &cap, 1);
10758 if (err < 0)
10759 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010760 err = snd_hda_get_connections(codec, cap, items,
10761 ARRAY_SIZE(items));
10762 if (err < 0)
10763 continue;
10764 for (j = 0; j < imux->num_items; j++)
10765 if (imux->items[j].index >= err)
10766 break;
10767 if (j < imux->num_items)
10768 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020010769 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10770 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010771 }
Takashi Iwai49535502009-06-30 15:28:30 +020010772 spec->adc_nids = spec->private_adc_nids;
10773 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010774 }
10775
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010776 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010010777
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010778 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010010779 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010780
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010781 if (board_config == ALC882_AUTO)
10782 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
10783
Takashi Iwai2134ea42008-01-10 16:53:55 +010010784 spec->vmaster_nid = 0x0c;
10785
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010786 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020010787 if (board_config == ALC882_AUTO)
10788 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010789#ifdef CONFIG_SND_HDA_POWER_SAVE
10790 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020010791 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010792#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010793
10794 return 0;
10795}
10796
Takashi Iwai49535502009-06-30 15:28:30 +020010797
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010798/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010799 * ALC262 support
10800 */
10801
10802#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10803#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10804
10805#define alc262_dac_nids alc260_dac_nids
10806#define alc262_adc_nids alc882_adc_nids
10807#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010808#define alc262_capsrc_nids alc882_capsrc_nids
10809#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010810
10811#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010812#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010813
Kailang Yang4e555fe2008-08-26 13:05:55 +020010814static hda_nid_t alc262_dmic_adc_nids[1] = {
10815 /* ADC0 */
10816 0x09
10817};
10818
10819static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10820
Kailang Yangdf694da2005-12-05 19:42:22 +010010821static struct snd_kcontrol_new alc262_base_mixer[] = {
10822 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10823 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10824 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10825 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10826 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10827 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10828 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10829 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010830 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010831 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10832 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010833 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010834 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10835 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10836 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10837 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010838 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010839};
10840
Takashi Iwaice875f02008-01-28 18:17:43 +010010841/* update HP, line and mono-out pins according to the master switch */
10842static void alc262_hp_master_update(struct hda_codec *codec)
10843{
10844 struct alc_spec *spec = codec->spec;
10845 int val = spec->master_sw;
10846
10847 /* HP & line-out */
10848 snd_hda_codec_write_cache(codec, 0x1b, 0,
10849 AC_VERB_SET_PIN_WIDGET_CONTROL,
10850 val ? PIN_HP : 0);
10851 snd_hda_codec_write_cache(codec, 0x15, 0,
10852 AC_VERB_SET_PIN_WIDGET_CONTROL,
10853 val ? PIN_HP : 0);
10854 /* mono (speaker) depending on the HP jack sense */
10855 val = val && !spec->jack_present;
10856 snd_hda_codec_write_cache(codec, 0x16, 0,
10857 AC_VERB_SET_PIN_WIDGET_CONTROL,
10858 val ? PIN_OUT : 0);
10859}
10860
10861static void alc262_hp_bpc_automute(struct hda_codec *codec)
10862{
10863 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010864
10865 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010866 alc262_hp_master_update(codec);
10867}
10868
10869static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10870{
10871 if ((res >> 26) != ALC880_HP_EVENT)
10872 return;
10873 alc262_hp_bpc_automute(codec);
10874}
10875
10876static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10877{
10878 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010879
10880 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010881 alc262_hp_master_update(codec);
10882}
10883
10884static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10885 unsigned int res)
10886{
10887 if ((res >> 26) != ALC880_HP_EVENT)
10888 return;
10889 alc262_hp_wildwest_automute(codec);
10890}
10891
Takashi Iwaib72519b2009-05-08 14:31:55 +020010892#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010893
10894static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10895 struct snd_ctl_elem_value *ucontrol)
10896{
10897 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10898 struct alc_spec *spec = codec->spec;
10899 int val = !!*ucontrol->value.integer.value;
10900
10901 if (val == spec->master_sw)
10902 return 0;
10903 spec->master_sw = val;
10904 alc262_hp_master_update(codec);
10905 return 1;
10906}
10907
Takashi Iwaib72519b2009-05-08 14:31:55 +020010908#define ALC262_HP_MASTER_SWITCH \
10909 { \
10910 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10911 .name = "Master Playback Switch", \
10912 .info = snd_ctl_boolean_mono_info, \
10913 .get = alc262_hp_master_sw_get, \
10914 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010915 }, \
10916 { \
10917 .iface = NID_MAPPING, \
10918 .name = "Master Playback Switch", \
10919 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010920 }
10921
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010922
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010923static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010924 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010925 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10926 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10927 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010928 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10929 HDA_OUTPUT),
10930 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10931 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010932 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10933 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010934 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010935 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10936 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010937 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010938 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10939 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10940 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10941 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010942 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10943 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10944 { } /* end */
10945};
10946
Kailang Yangcd7509a2007-01-26 18:33:17 +010010947static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010948 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010949 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10950 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10951 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10952 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010953 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10954 HDA_OUTPUT),
10955 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10956 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010957 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10958 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010959 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010960 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10961 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10962 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10963 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010964 { } /* end */
10965};
10966
10967static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10968 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10969 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010970 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010971 { } /* end */
10972};
10973
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010974/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010975static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010976{
10977 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010978
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010979 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010010980 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010981}
10982
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010983static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010984 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10985 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010986 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10987 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10989 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10990 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10991 { } /* end */
10992};
10993
10994static struct hda_verb alc262_hp_t5735_verbs[] = {
10995 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10996 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10997
10998 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10999 { }
11000};
11001
Kailang Yang8c427222008-01-10 13:03:59 +010011002static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011003 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11004 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011005 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11006 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011007 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11008 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11009 { } /* end */
11010};
11011
11012static struct hda_verb alc262_hp_rp5700_verbs[] = {
11013 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11014 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11015 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11016 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11017 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11018 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11019 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11020 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11021 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11022 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11023 {}
11024};
11025
11026static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11027 .num_items = 1,
11028 .items = {
11029 { "Line", 0x1 },
11030 },
11031};
11032
Takashi Iwai42171c12009-05-08 14:11:43 +020011033/* bind hp and internal speaker mute (with plug check) as master switch */
11034static void alc262_hippo_master_update(struct hda_codec *codec)
11035{
11036 struct alc_spec *spec = codec->spec;
11037 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11038 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11039 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11040 unsigned int mute;
11041
11042 /* HP */
11043 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11044 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11045 HDA_AMP_MUTE, mute);
11046 /* mute internal speaker per jack sense */
11047 if (spec->jack_present)
11048 mute = HDA_AMP_MUTE;
11049 if (line_nid)
11050 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11051 HDA_AMP_MUTE, mute);
11052 if (speaker_nid && speaker_nid != line_nid)
11053 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11054 HDA_AMP_MUTE, mute);
11055}
11056
11057#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11058
11059static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11060 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011061{
11062 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011063 struct alc_spec *spec = codec->spec;
11064 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011065
Takashi Iwai42171c12009-05-08 14:11:43 +020011066 if (val == spec->master_sw)
11067 return 0;
11068 spec->master_sw = val;
11069 alc262_hippo_master_update(codec);
11070 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011071}
Takashi Iwai5b319542007-07-26 11:49:22 +020011072
Takashi Iwai42171c12009-05-08 14:11:43 +020011073#define ALC262_HIPPO_MASTER_SWITCH \
11074 { \
11075 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11076 .name = "Master Playback Switch", \
11077 .info = snd_ctl_boolean_mono_info, \
11078 .get = alc262_hippo_master_sw_get, \
11079 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011080 }, \
11081 { \
11082 .iface = NID_MAPPING, \
11083 .name = "Master Playback Switch", \
11084 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11085 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011086 }
11087
11088static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11089 ALC262_HIPPO_MASTER_SWITCH,
11090 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11091 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11092 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11093 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11094 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11095 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11096 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11097 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11098 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11099 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11100 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11101 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11102 { } /* end */
11103};
11104
11105static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11106 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11107 ALC262_HIPPO_MASTER_SWITCH,
11108 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11109 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11110 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11111 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11112 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11113 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11114 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11115 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11116 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11117 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11118 { } /* end */
11119};
11120
11121/* mute/unmute internal speaker according to the hp jack and mute state */
11122static void alc262_hippo_automute(struct hda_codec *codec)
11123{
11124 struct alc_spec *spec = codec->spec;
11125 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011126
Wu Fengguang864f92b2009-11-18 12:38:02 +080011127 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011128 alc262_hippo_master_update(codec);
11129}
11130
11131static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11132{
11133 if ((res >> 26) != ALC880_HP_EVENT)
11134 return;
11135 alc262_hippo_automute(codec);
11136}
11137
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011138static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011139{
11140 struct alc_spec *spec = codec->spec;
11141
11142 spec->autocfg.hp_pins[0] = 0x15;
11143 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011144}
11145
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011146static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011147{
11148 struct alc_spec *spec = codec->spec;
11149
11150 spec->autocfg.hp_pins[0] = 0x1b;
11151 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011152}
11153
11154
Kailang Yang272a5272007-05-14 11:00:38 +020011155static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011156 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011157 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011158 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11159 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11160 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11161 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11162 { } /* end */
11163};
11164
Kailang Yang83c34212007-07-05 11:43:05 +020011165static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011166 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11167 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011168 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11169 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11170 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11171 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11172 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11173 { } /* end */
11174};
Kailang Yang272a5272007-05-14 11:00:38 +020011175
Tony Vroonba340e82009-02-02 19:01:30 +000011176static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11177 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11178 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11179 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11180 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11181 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11182 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11183 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11184 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11185 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11186 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11187 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11188 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11189 { } /* end */
11190};
11191
11192static struct hda_verb alc262_tyan_verbs[] = {
11193 /* Headphone automute */
11194 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11195 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11196 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11197
11198 /* P11 AUX_IN, white 4-pin connector */
11199 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11200 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11201 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11202 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11203
11204 {}
11205};
11206
11207/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011208static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011209{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011210 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011211
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011212 spec->autocfg.hp_pins[0] = 0x1b;
11213 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011214}
11215
Tony Vroonba340e82009-02-02 19:01:30 +000011216
Kailang Yangdf694da2005-12-05 19:42:22 +010011217#define alc262_capture_mixer alc882_capture_mixer
11218#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11219
11220/*
11221 * generic initialization of ADC, input mixers and output mixers
11222 */
11223static struct hda_verb alc262_init_verbs[] = {
11224 /*
11225 * Unmute ADC0-2 and set the default input to mic-in
11226 */
11227 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11228 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11229 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11230 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11231 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11232 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11233
Takashi Iwaicb53c622007-08-10 17:21:45 +020011234 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011235 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011236 * Note: PASD motherboards uses the Line In 2 as the input for
11237 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011238 */
11239 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011240 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11241 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11242 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11243 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11244 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011245
11246 /*
11247 * Set up output mixers (0x0c - 0x0e)
11248 */
11249 /* set vol=0 to output mixers */
11250 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11251 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11252 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11253 /* set up input amps for analog loopback */
11254 /* Amp Indices: DAC = 0, mixer = 1 */
11255 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11257 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11258 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11259 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11260 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11261
11262 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11263 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11264 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11265 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11266 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11267 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11268
11269 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11270 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11271 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11272 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11273 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011274
Kailang Yangdf694da2005-12-05 19:42:22 +010011275 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11276 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011277
Kailang Yangdf694da2005-12-05 19:42:22 +010011278 /* FIXME: use matrix-type input source selection */
11279 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11280 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11281 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11282 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11283 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11284 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11285 /* Input mixer2 */
11286 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11287 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11288 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11289 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11290 /* Input mixer3 */
11291 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11292 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11293 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011294 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011295
11296 { }
11297};
11298
Kailang Yang4e555fe2008-08-26 13:05:55 +020011299static struct hda_verb alc262_eapd_verbs[] = {
11300 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11301 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11302 { }
11303};
11304
Kailang Yangccc656c2006-10-17 12:32:26 +020011305static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11306 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11307 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11308 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11309
11310 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11311 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11312 {}
11313};
11314
Kailang Yang272a5272007-05-14 11:00:38 +020011315static struct hda_verb alc262_sony_unsol_verbs[] = {
11316 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11317 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11318 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11319
11320 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11321 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011322 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011323};
11324
Kailang Yang4e555fe2008-08-26 13:05:55 +020011325static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11326 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11327 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11328 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11329 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11330 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011331 { } /* end */
11332};
11333
11334static struct hda_verb alc262_toshiba_s06_verbs[] = {
11335 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11336 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11337 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11338 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11339 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11340 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11341 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11342 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11343 {}
11344};
11345
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011346static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011347{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011348 struct alc_spec *spec = codec->spec;
11349
11350 spec->autocfg.hp_pins[0] = 0x15;
11351 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011352 spec->ext_mic.pin = 0x18;
11353 spec->ext_mic.mux_idx = 0;
11354 spec->int_mic.pin = 0x12;
11355 spec->int_mic.mux_idx = 9;
11356 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011357}
11358
Takashi Iwai834be882006-03-01 14:16:17 +010011359/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011360 * nec model
11361 * 0x15 = headphone
11362 * 0x16 = internal speaker
11363 * 0x18 = external mic
11364 */
11365
11366static struct snd_kcontrol_new alc262_nec_mixer[] = {
11367 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11368 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11369
11370 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11371 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11372 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11373
11374 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11375 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11376 { } /* end */
11377};
11378
11379static struct hda_verb alc262_nec_verbs[] = {
11380 /* Unmute Speaker */
11381 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11382
11383 /* Headphone */
11384 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11385 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11386
11387 /* External mic to headphone */
11388 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11389 /* External mic to speaker */
11390 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11391 {}
11392};
11393
11394/*
Takashi Iwai834be882006-03-01 14:16:17 +010011395 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011396 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11397 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011398 */
11399
11400#define ALC_HP_EVENT 0x37
11401
11402static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11403 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11404 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011405 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11406 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011407 {}
11408};
11409
Jiang zhe0e31daf2008-03-20 12:12:39 +010011410static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11411 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11412 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11413 {}
11414};
11415
Daniel T Chene2595322009-12-19 18:19:02 -050011416static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11417 /* Front Mic pin: input vref at 50% */
11418 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11419 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11420 {}
11421};
11422
Takashi Iwai834be882006-03-01 14:16:17 +010011423static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011424 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011425 .items = {
11426 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011427 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011428 { "CD", 0x4 },
11429 },
11430};
11431
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011432static struct hda_input_mux alc262_HP_capture_source = {
11433 .num_items = 5,
11434 .items = {
11435 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011436 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011437 { "Line", 0x2 },
11438 { "CD", 0x4 },
11439 { "AUX IN", 0x6 },
11440 },
11441};
11442
zhejiangaccbe492007-08-31 12:36:05 +020011443static struct hda_input_mux alc262_HP_D7000_capture_source = {
11444 .num_items = 4,
11445 .items = {
11446 { "Mic", 0x0 },
11447 { "Front Mic", 0x2 },
11448 { "Line", 0x1 },
11449 { "CD", 0x4 },
11450 },
11451};
11452
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011453/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011454static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11455{
11456 struct alc_spec *spec = codec->spec;
11457 unsigned int mute;
11458
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011459 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011460 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11461 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011462 spec->sense_updated = 1;
11463 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011464 /* unmute internal speaker only if both HPs are unplugged and
11465 * master switch is on
11466 */
11467 if (spec->jack_present)
11468 mute = HDA_AMP_MUTE;
11469 else
Takashi Iwai834be882006-03-01 14:16:17 +010011470 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011471 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11472 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011473}
11474
11475/* unsolicited event for HP jack sensing */
11476static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11477 unsigned int res)
11478{
11479 if ((res >> 26) != ALC_HP_EVENT)
11480 return;
11481 alc262_fujitsu_automute(codec, 1);
11482}
11483
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011484static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11485{
11486 alc262_fujitsu_automute(codec, 1);
11487}
11488
Takashi Iwai834be882006-03-01 14:16:17 +010011489/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011490static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11491 .ops = &snd_hda_bind_vol,
11492 .values = {
11493 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11494 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11495 0
11496 },
11497};
Takashi Iwai834be882006-03-01 14:16:17 +010011498
Jiang zhe0e31daf2008-03-20 12:12:39 +010011499/* mute/unmute internal speaker according to the hp jack and mute state */
11500static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11501{
11502 struct alc_spec *spec = codec->spec;
11503 unsigned int mute;
11504
11505 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011506 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011507 spec->sense_updated = 1;
11508 }
11509 if (spec->jack_present) {
11510 /* mute internal speaker */
11511 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11512 HDA_AMP_MUTE, HDA_AMP_MUTE);
11513 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11514 HDA_AMP_MUTE, HDA_AMP_MUTE);
11515 } else {
11516 /* unmute internal speaker if necessary */
11517 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11518 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11519 HDA_AMP_MUTE, mute);
11520 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11521 HDA_AMP_MUTE, mute);
11522 }
11523}
11524
11525/* unsolicited event for HP jack sensing */
11526static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11527 unsigned int res)
11528{
11529 if ((res >> 26) != ALC_HP_EVENT)
11530 return;
11531 alc262_lenovo_3000_automute(codec, 1);
11532}
11533
Takashi Iwai8de56b72009-07-24 16:51:47 +020011534static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11535 int dir, int idx, long *valp)
11536{
11537 int i, change = 0;
11538
11539 for (i = 0; i < 2; i++, valp++)
11540 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11541 HDA_AMP_MUTE,
11542 *valp ? 0 : HDA_AMP_MUTE);
11543 return change;
11544}
11545
Takashi Iwai834be882006-03-01 14:16:17 +010011546/* bind hp and internal speaker mute (with plug check) */
11547static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11548 struct snd_ctl_elem_value *ucontrol)
11549{
11550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11551 long *valp = ucontrol->value.integer.value;
11552 int change;
11553
Takashi Iwai8de56b72009-07-24 16:51:47 +020011554 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11555 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011556 if (change)
11557 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011558 return change;
11559}
11560
11561static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011562 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011563 {
11564 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11565 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011566 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011567 .info = snd_hda_mixer_amp_switch_info,
11568 .get = snd_hda_mixer_amp_switch_get,
11569 .put = alc262_fujitsu_master_sw_put,
11570 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11571 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011572 {
11573 .iface = NID_MAPPING,
11574 .name = "Master Playback Switch",
11575 .private_value = 0x1b,
11576 },
Takashi Iwai834be882006-03-01 14:16:17 +010011577 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11578 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11579 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11580 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11581 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011582 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11583 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11584 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011585 { } /* end */
11586};
11587
Jiang zhe0e31daf2008-03-20 12:12:39 +010011588/* bind hp and internal speaker mute (with plug check) */
11589static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11590 struct snd_ctl_elem_value *ucontrol)
11591{
11592 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11593 long *valp = ucontrol->value.integer.value;
11594 int change;
11595
Takashi Iwai8de56b72009-07-24 16:51:47 +020011596 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011597 if (change)
11598 alc262_lenovo_3000_automute(codec, 0);
11599 return change;
11600}
11601
11602static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11603 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11604 {
11605 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11606 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011607 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011608 .info = snd_hda_mixer_amp_switch_info,
11609 .get = snd_hda_mixer_amp_switch_get,
11610 .put = alc262_lenovo_3000_master_sw_put,
11611 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11612 },
11613 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11614 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11615 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11616 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11617 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11618 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11619 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11620 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11621 { } /* end */
11622};
11623
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011624static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11625 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011626 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011627 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11628 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11629 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11630 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11631 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11632 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11633 { } /* end */
11634};
11635
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011636/* additional init verbs for Benq laptops */
11637static struct hda_verb alc262_EAPD_verbs[] = {
11638 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11639 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11640 {}
11641};
11642
Kailang Yang83c34212007-07-05 11:43:05 +020011643static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11644 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11645 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11646
11647 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11648 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11649 {}
11650};
11651
Tobin Davisf651b502007-10-26 12:40:47 +020011652/* Samsung Q1 Ultra Vista model setup */
11653static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011654 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11655 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011656 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11657 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11658 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011659 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011660 { } /* end */
11661};
11662
11663static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011664 /* output mixer */
11665 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11666 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11667 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11668 /* speaker */
11669 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11670 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11671 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11672 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11673 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011674 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011675 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11676 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11677 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11678 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11679 /* internal mic */
11680 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11681 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11682 /* ADC, choose mic */
11683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11684 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11685 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11686 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11687 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11688 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11689 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11690 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11691 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11692 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011693 {}
11694};
11695
Tobin Davisf651b502007-10-26 12:40:47 +020011696/* mute/unmute internal speaker according to the hp jack and mute state */
11697static void alc262_ultra_automute(struct hda_codec *codec)
11698{
11699 struct alc_spec *spec = codec->spec;
11700 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011701
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011702 mute = 0;
11703 /* auto-mute only when HP is used as HP */
11704 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011705 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011706 if (spec->jack_present)
11707 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011708 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011709 /* mute/unmute internal speaker */
11710 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11711 HDA_AMP_MUTE, mute);
11712 /* mute/unmute HP */
11713 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11714 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011715}
11716
11717/* unsolicited event for HP jack sensing */
11718static void alc262_ultra_unsol_event(struct hda_codec *codec,
11719 unsigned int res)
11720{
11721 if ((res >> 26) != ALC880_HP_EVENT)
11722 return;
11723 alc262_ultra_automute(codec);
11724}
11725
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011726static struct hda_input_mux alc262_ultra_capture_source = {
11727 .num_items = 2,
11728 .items = {
11729 { "Mic", 0x1 },
11730 { "Headphone", 0x7 },
11731 },
11732};
11733
11734static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11735 struct snd_ctl_elem_value *ucontrol)
11736{
11737 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11738 struct alc_spec *spec = codec->spec;
11739 int ret;
11740
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011741 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011742 if (!ret)
11743 return 0;
11744 /* reprogram the HP pin as mic or HP according to the input source */
11745 snd_hda_codec_write_cache(codec, 0x15, 0,
11746 AC_VERB_SET_PIN_WIDGET_CONTROL,
11747 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11748 alc262_ultra_automute(codec); /* mute/unmute HP */
11749 return ret;
11750}
11751
11752static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11753 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11754 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11755 {
11756 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11757 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011758 .info = alc_mux_enum_info,
11759 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011760 .put = alc262_ultra_mux_enum_put,
11761 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011762 {
11763 .iface = NID_MAPPING,
11764 .name = "Capture Source",
11765 .private_value = 0x15,
11766 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011767 { } /* end */
11768};
11769
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011770/* We use two mixers depending on the output pin; 0x16 is a mono output
11771 * and thus it's bound with a different mixer.
11772 * This function returns which mixer amp should be used.
11773 */
11774static int alc262_check_volbit(hda_nid_t nid)
11775{
11776 if (!nid)
11777 return 0;
11778 else if (nid == 0x16)
11779 return 2;
11780 else
11781 return 1;
11782}
11783
11784static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11785 const char *pfx, int *vbits)
11786{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011787 unsigned long val;
11788 int vbit;
11789
11790 vbit = alc262_check_volbit(nid);
11791 if (!vbit)
11792 return 0;
11793 if (*vbits & vbit) /* a volume control for this mixer already there */
11794 return 0;
11795 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011796 if (vbit == 2)
11797 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11798 else
11799 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011800 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011801}
11802
11803static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11804 const char *pfx)
11805{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011806 unsigned long val;
11807
11808 if (!nid)
11809 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011810 if (nid == 0x16)
11811 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11812 else
11813 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011814 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011815}
11816
Kailang Yangdf694da2005-12-05 19:42:22 +010011817/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011818static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11819 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011820{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011821 const char *pfx;
11822 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011823 int err;
11824
11825 spec->multiout.num_dacs = 1; /* only use one dac */
11826 spec->multiout.dac_nids = spec->private_dac_nids;
11827 spec->multiout.dac_nids[0] = 2;
11828
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011829 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11830 pfx = "Master";
11831 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11832 pfx = "Speaker";
11833 else
11834 pfx = "Front";
11835 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11836 if (err < 0)
11837 return err;
11838 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11839 if (err < 0)
11840 return err;
11841 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11842 if (err < 0)
11843 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011844
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011845 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11846 alc262_check_volbit(cfg->speaker_pins[0]) |
11847 alc262_check_volbit(cfg->hp_pins[0]);
11848 if (vbits == 1 || vbits == 2)
11849 pfx = "Master"; /* only one mixer is used */
11850 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11851 pfx = "Speaker";
11852 else
11853 pfx = "Front";
11854 vbits = 0;
11855 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11856 if (err < 0)
11857 return err;
11858 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11859 &vbits);
11860 if (err < 0)
11861 return err;
11862 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11863 &vbits);
11864 if (err < 0)
11865 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011866 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011867}
11868
Takashi Iwai05f5f472009-08-25 13:10:18 +020011869#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010011870 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011871
11872/*
11873 * generic initialization of ADC, input mixers and output mixers
11874 */
11875static struct hda_verb alc262_volume_init_verbs[] = {
11876 /*
11877 * Unmute ADC0-2 and set the default input to mic-in
11878 */
11879 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11880 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11881 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11882 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11883 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11884 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11885
Takashi Iwaicb53c622007-08-10 17:21:45 +020011886 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011887 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011888 * Note: PASD motherboards uses the Line In 2 as the input for
11889 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011890 */
11891 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011892 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11893 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11894 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11895 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11896 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011897
11898 /*
11899 * Set up output mixers (0x0c - 0x0f)
11900 */
11901 /* set vol=0 to output mixers */
11902 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11903 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11904 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011905
Kailang Yangdf694da2005-12-05 19:42:22 +010011906 /* set up input amps for analog loopback */
11907 /* Amp Indices: DAC = 0, mixer = 1 */
11908 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11909 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11910 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11911 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11912 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11913 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11914
11915 /* FIXME: use matrix-type input source selection */
11916 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11917 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11918 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11919 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11920 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11921 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11922 /* Input mixer2 */
11923 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11924 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11925 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11926 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11927 /* Input mixer3 */
11928 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11929 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11930 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11931 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11932
11933 { }
11934};
11935
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011936static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11937 /*
11938 * Unmute ADC0-2 and set the default input to mic-in
11939 */
11940 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11941 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11942 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11943 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11944 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11945 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11946
Takashi Iwaicb53c622007-08-10 17:21:45 +020011947 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011948 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011949 * Note: PASD motherboards uses the Line In 2 as the input for
11950 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011951 */
11952 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011953 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11954 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11955 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11956 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11957 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11958 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11959 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011960
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011961 /*
11962 * Set up output mixers (0x0c - 0x0e)
11963 */
11964 /* set vol=0 to output mixers */
11965 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11966 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11967 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11968
11969 /* set up input amps for analog loopback */
11970 /* Amp Indices: DAC = 0, mixer = 1 */
11971 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11972 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11973 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11974 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11975 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11976 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11977
Takashi Iwaice875f02008-01-28 18:17:43 +010011978 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011979 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11980 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11981
11982 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11983 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11984
11985 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11986 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11987
11988 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11989 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11990 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11991 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11992 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11993
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011994 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011995 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11996 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011997 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011998 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11999 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12000
12001
12002 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012003 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12004 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012005 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012006 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12007 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12008 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12009 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12010 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12011 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12012 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12013 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012014 /* Input mixer2 */
12015 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012016 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12017 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12018 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12019 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12020 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12021 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12022 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12023 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012024 /* Input mixer3 */
12025 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012026 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12027 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12028 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12029 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12030 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12031 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12033 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012034
Takashi Iwaice875f02008-01-28 18:17:43 +010012035 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12036
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012037 { }
12038};
12039
Kailang Yangcd7509a2007-01-26 18:33:17 +010012040static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12041 /*
12042 * Unmute ADC0-2 and set the default input to mic-in
12043 */
12044 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12045 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12046 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12047 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12048 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12049 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12050
Takashi Iwaicb53c622007-08-10 17:21:45 +020012051 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012052 * mixer widget
12053 * Note: PASD motherboards uses the Line In 2 as the input for front
12054 * panel mic (mic 2)
12055 */
12056 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012057 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12058 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12059 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12060 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12061 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12062 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12063 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12064 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012065 /*
12066 * Set up output mixers (0x0c - 0x0e)
12067 */
12068 /* set vol=0 to output mixers */
12069 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12070 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12071 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12072
12073 /* set up input amps for analog loopback */
12074 /* Amp Indices: DAC = 0, mixer = 1 */
12075 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12076 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12077 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12078 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12079 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12080 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12081
12082
12083 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12084 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12085 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12086 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12087 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12088 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12089 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12090
12091 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12092 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12093
12094 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12095 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12096
12097 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12098 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12099 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12100 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12101 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12102 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12103
12104 /* FIXME: use matrix-type input source selection */
12105 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12106 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12107 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12108 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12109 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12110 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12111 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12112 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12113 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12114 /* Input mixer2 */
12115 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12116 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12117 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12118 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12119 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12120 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12121 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12122 /* Input mixer3 */
12123 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12124 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12125 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12126 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12127 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12128 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12129 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12130
Takashi Iwaice875f02008-01-28 18:17:43 +010012131 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12132
Kailang Yangcd7509a2007-01-26 18:33:17 +010012133 { }
12134};
12135
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012136static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12137
12138 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12139 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12140 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12141
12142 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12143 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12144 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12145 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12146
12147 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12148 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12149 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12150 {}
12151};
12152
12153
Takashi Iwaicb53c622007-08-10 17:21:45 +020012154#ifdef CONFIG_SND_HDA_POWER_SAVE
12155#define alc262_loopbacks alc880_loopbacks
12156#endif
12157
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012158/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012159#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12160#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12161#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12162#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12163
12164/*
12165 * BIOS auto configuration
12166 */
12167static int alc262_parse_auto_config(struct hda_codec *codec)
12168{
12169 struct alc_spec *spec = codec->spec;
12170 int err;
12171 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12172
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012173 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12174 alc262_ignore);
12175 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012176 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012177 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012178 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012179 spec->multiout.max_channels = 2;
12180 spec->no_analog = 1;
12181 goto dig_only;
12182 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012183 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012184 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012185 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12186 if (err < 0)
12187 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012188 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012189 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012190 return err;
12191
12192 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12193
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012194 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012195 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012196
Takashi Iwai603c4012008-07-30 15:01:44 +020012197 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012198 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012199
Takashi Iwaid88897e2008-10-31 15:01:37 +010012200 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012201 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012202 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012203
Takashi Iwai776e1842007-08-29 15:07:11 +020012204 err = alc_auto_add_mic_boost(codec);
12205 if (err < 0)
12206 return err;
12207
Kailang Yang6227cdc2010-02-25 08:36:52 +010012208 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012209
Kailang Yangdf694da2005-12-05 19:42:22 +010012210 return 1;
12211}
12212
12213#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12214#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12215#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012216#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012217
12218
12219/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012220static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012221{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012222 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012223 alc262_auto_init_multi_out(codec);
12224 alc262_auto_init_hp_out(codec);
12225 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012226 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012227 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012228 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012229 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012230}
12231
12232/*
12233 * configuration and preset
12234 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012235static const char *alc262_models[ALC262_MODEL_LAST] = {
12236 [ALC262_BASIC] = "basic",
12237 [ALC262_HIPPO] = "hippo",
12238 [ALC262_HIPPO_1] = "hippo_1",
12239 [ALC262_FUJITSU] = "fujitsu",
12240 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012241 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012242 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012243 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012244 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012245 [ALC262_BENQ_T31] = "benq-t31",
12246 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012247 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012248 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012249 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012250 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012251 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012252 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012253 [ALC262_AUTO] = "auto",
12254};
12255
12256static struct snd_pci_quirk alc262_cfg_tbl[] = {
12257 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012258 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012259 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12260 ALC262_HP_BPC),
12261 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12262 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012263 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12264 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012265 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012266 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012267 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012268 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012269 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012270 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012271 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012272 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012273 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12274 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12275 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012276 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12277 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012278 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012279 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012280 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012281 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012282 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012283 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012284 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012285 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012286#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012287 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12288 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012289#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012290 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012291 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012292 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012293 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012294 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012295 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012296 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12297 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012298 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012299 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012300 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012301 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012302 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012303 {}
12304};
12305
12306static struct alc_config_preset alc262_presets[] = {
12307 [ALC262_BASIC] = {
12308 .mixers = { alc262_base_mixer },
12309 .init_verbs = { alc262_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,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012315 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012316 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012317 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012318 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012319 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012320 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12321 .dac_nids = alc262_dac_nids,
12322 .hp_nid = 0x03,
12323 .dig_out_nid = ALC262_DIGOUT_NID,
12324 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12325 .channel_mode = alc262_modes,
12326 .input_mux = &alc262_capture_source,
12327 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012328 .setup = alc262_hippo_setup,
12329 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012330 },
12331 [ALC262_HIPPO_1] = {
12332 .mixers = { alc262_hippo1_mixer },
12333 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12334 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12335 .dac_nids = alc262_dac_nids,
12336 .hp_nid = 0x02,
12337 .dig_out_nid = ALC262_DIGOUT_NID,
12338 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12339 .channel_mode = alc262_modes,
12340 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012341 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012342 .setup = alc262_hippo1_setup,
12343 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012344 },
Takashi Iwai834be882006-03-01 14:16:17 +010012345 [ALC262_FUJITSU] = {
12346 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012347 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12348 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012349 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12350 .dac_nids = alc262_dac_nids,
12351 .hp_nid = 0x03,
12352 .dig_out_nid = ALC262_DIGOUT_NID,
12353 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12354 .channel_mode = alc262_modes,
12355 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012356 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012357 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012358 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012359 [ALC262_HP_BPC] = {
12360 .mixers = { alc262_HP_BPC_mixer },
12361 .init_verbs = { alc262_HP_BPC_init_verbs },
12362 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12363 .dac_nids = alc262_dac_nids,
12364 .hp_nid = 0x03,
12365 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12366 .channel_mode = alc262_modes,
12367 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012368 .unsol_event = alc262_hp_bpc_unsol_event,
12369 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012370 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012371 [ALC262_HP_BPC_D7000_WF] = {
12372 .mixers = { alc262_HP_BPC_WildWest_mixer },
12373 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12374 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12375 .dac_nids = alc262_dac_nids,
12376 .hp_nid = 0x03,
12377 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12378 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012379 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012380 .unsol_event = alc262_hp_wildwest_unsol_event,
12381 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012382 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012383 [ALC262_HP_BPC_D7000_WL] = {
12384 .mixers = { alc262_HP_BPC_WildWest_mixer,
12385 alc262_HP_BPC_WildWest_option_mixer },
12386 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12387 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12388 .dac_nids = alc262_dac_nids,
12389 .hp_nid = 0x03,
12390 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12391 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012392 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012393 .unsol_event = alc262_hp_wildwest_unsol_event,
12394 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012395 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012396 [ALC262_HP_TC_T5735] = {
12397 .mixers = { alc262_hp_t5735_mixer },
12398 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12399 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12400 .dac_nids = alc262_dac_nids,
12401 .hp_nid = 0x03,
12402 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12403 .channel_mode = alc262_modes,
12404 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012405 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012406 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012407 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012408 },
12409 [ALC262_HP_RP5700] = {
12410 .mixers = { alc262_hp_rp5700_mixer },
12411 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12412 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12413 .dac_nids = alc262_dac_nids,
12414 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12415 .channel_mode = alc262_modes,
12416 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012417 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012418 [ALC262_BENQ_ED8] = {
12419 .mixers = { alc262_base_mixer },
12420 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12421 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12422 .dac_nids = alc262_dac_nids,
12423 .hp_nid = 0x03,
12424 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12425 .channel_mode = alc262_modes,
12426 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012427 },
Kailang Yang272a5272007-05-14 11:00:38 +020012428 [ALC262_SONY_ASSAMD] = {
12429 .mixers = { alc262_sony_mixer },
12430 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12431 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12432 .dac_nids = alc262_dac_nids,
12433 .hp_nid = 0x02,
12434 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12435 .channel_mode = alc262_modes,
12436 .input_mux = &alc262_capture_source,
12437 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012438 .setup = alc262_hippo_setup,
12439 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012440 },
12441 [ALC262_BENQ_T31] = {
12442 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012443 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12444 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012445 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12446 .dac_nids = alc262_dac_nids,
12447 .hp_nid = 0x03,
12448 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12449 .channel_mode = alc262_modes,
12450 .input_mux = &alc262_capture_source,
12451 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012452 .setup = alc262_hippo_setup,
12453 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012454 },
Tobin Davisf651b502007-10-26 12:40:47 +020012455 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012456 .mixers = { alc262_ultra_mixer },
12457 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012458 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012459 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12460 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012461 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12462 .channel_mode = alc262_modes,
12463 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012464 .adc_nids = alc262_adc_nids, /* ADC0 */
12465 .capsrc_nids = alc262_capsrc_nids,
12466 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012467 .unsol_event = alc262_ultra_unsol_event,
12468 .init_hook = alc262_ultra_automute,
12469 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012470 [ALC262_LENOVO_3000] = {
12471 .mixers = { alc262_lenovo_3000_mixer },
12472 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012473 alc262_lenovo_3000_unsol_verbs,
12474 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012475 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12476 .dac_nids = alc262_dac_nids,
12477 .hp_nid = 0x03,
12478 .dig_out_nid = ALC262_DIGOUT_NID,
12479 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12480 .channel_mode = alc262_modes,
12481 .input_mux = &alc262_fujitsu_capture_source,
12482 .unsol_event = alc262_lenovo_3000_unsol_event,
12483 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012484 [ALC262_NEC] = {
12485 .mixers = { alc262_nec_mixer },
12486 .init_verbs = { alc262_nec_verbs },
12487 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12488 .dac_nids = alc262_dac_nids,
12489 .hp_nid = 0x03,
12490 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12491 .channel_mode = alc262_modes,
12492 .input_mux = &alc262_capture_source,
12493 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012494 [ALC262_TOSHIBA_S06] = {
12495 .mixers = { alc262_toshiba_s06_mixer },
12496 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12497 alc262_eapd_verbs },
12498 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12499 .capsrc_nids = alc262_dmic_capsrc_nids,
12500 .dac_nids = alc262_dac_nids,
12501 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012502 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012503 .dig_out_nid = ALC262_DIGOUT_NID,
12504 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12505 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012506 .unsol_event = alc_sku_unsol_event,
12507 .setup = alc262_toshiba_s06_setup,
12508 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012509 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012510 [ALC262_TOSHIBA_RX1] = {
12511 .mixers = { alc262_toshiba_rx1_mixer },
12512 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12513 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12514 .dac_nids = alc262_dac_nids,
12515 .hp_nid = 0x03,
12516 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12517 .channel_mode = alc262_modes,
12518 .input_mux = &alc262_capture_source,
12519 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012520 .setup = alc262_hippo_setup,
12521 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012522 },
Tony Vroonba340e82009-02-02 19:01:30 +000012523 [ALC262_TYAN] = {
12524 .mixers = { alc262_tyan_mixer },
12525 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12526 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12527 .dac_nids = alc262_dac_nids,
12528 .hp_nid = 0x02,
12529 .dig_out_nid = ALC262_DIGOUT_NID,
12530 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12531 .channel_mode = alc262_modes,
12532 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012533 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012534 .setup = alc262_tyan_setup,
12535 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012536 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012537};
12538
12539static int patch_alc262(struct hda_codec *codec)
12540{
12541 struct alc_spec *spec;
12542 int board_config;
12543 int err;
12544
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012545 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012546 if (spec == NULL)
12547 return -ENOMEM;
12548
12549 codec->spec = spec;
12550#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012551 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12552 * under-run
12553 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012554 {
12555 int tmp;
12556 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12557 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12558 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12559 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12560 }
12561#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012562 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012563
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012564 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12565
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012566 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12567 alc262_models,
12568 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012569
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012570 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012571 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12572 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012573 board_config = ALC262_AUTO;
12574 }
12575
12576 if (board_config == ALC262_AUTO) {
12577 /* automatic parse from the BIOS config */
12578 err = alc262_parse_auto_config(codec);
12579 if (err < 0) {
12580 alc_free(codec);
12581 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012582 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012583 printk(KERN_INFO
12584 "hda_codec: Cannot set up configuration "
12585 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012586 board_config = ALC262_BASIC;
12587 }
12588 }
12589
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012590 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012591 err = snd_hda_attach_beep_device(codec, 0x1);
12592 if (err < 0) {
12593 alc_free(codec);
12594 return err;
12595 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012596 }
12597
Kailang Yangdf694da2005-12-05 19:42:22 +010012598 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012599 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012600
Kailang Yangdf694da2005-12-05 19:42:22 +010012601 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12602 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012603
Kailang Yangdf694da2005-12-05 19:42:22 +010012604 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12605 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12606
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012607 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012608 int i;
12609 /* check whether the digital-mic has to be supported */
12610 for (i = 0; i < spec->input_mux->num_items; i++) {
12611 if (spec->input_mux->items[i].index >= 9)
12612 break;
12613 }
12614 if (i < spec->input_mux->num_items) {
12615 /* use only ADC0 */
12616 spec->adc_nids = alc262_dmic_adc_nids;
12617 spec->num_adc_nids = 1;
12618 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012619 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012620 /* all analog inputs */
12621 /* check whether NID 0x07 is valid */
12622 unsigned int wcap = get_wcaps(codec, 0x07);
12623
12624 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012625 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012626 if (wcap != AC_WID_AUD_IN) {
12627 spec->adc_nids = alc262_adc_nids_alt;
12628 spec->num_adc_nids =
12629 ARRAY_SIZE(alc262_adc_nids_alt);
12630 spec->capsrc_nids = alc262_capsrc_nids_alt;
12631 } else {
12632 spec->adc_nids = alc262_adc_nids;
12633 spec->num_adc_nids =
12634 ARRAY_SIZE(alc262_adc_nids);
12635 spec->capsrc_nids = alc262_capsrc_nids;
12636 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012637 }
12638 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012639 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012640 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012641 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012642 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012643
Takashi Iwai2134ea42008-01-10 16:53:55 +010012644 spec->vmaster_nid = 0x0c;
12645
Kailang Yangdf694da2005-12-05 19:42:22 +010012646 codec->patch_ops = alc_patch_ops;
12647 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012648 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012649#ifdef CONFIG_SND_HDA_POWER_SAVE
12650 if (!spec->loopback.amplist)
12651 spec->loopback.amplist = alc262_loopbacks;
12652#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012653
Kailang Yangdf694da2005-12-05 19:42:22 +010012654 return 0;
12655}
12656
Kailang Yangdf694da2005-12-05 19:42:22 +010012657/*
Kailang Yanga361d842007-06-05 12:30:55 +020012658 * ALC268 channel source setting (2 channel)
12659 */
12660#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12661#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012662
Kailang Yanga361d842007-06-05 12:30:55 +020012663static hda_nid_t alc268_dac_nids[2] = {
12664 /* front, hp */
12665 0x02, 0x03
12666};
12667
12668static hda_nid_t alc268_adc_nids[2] = {
12669 /* ADC0-1 */
12670 0x08, 0x07
12671};
12672
12673static hda_nid_t alc268_adc_nids_alt[1] = {
12674 /* ADC0 */
12675 0x08
12676};
12677
Takashi Iwaie1406342008-02-11 18:32:32 +010012678static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12679
Kailang Yanga361d842007-06-05 12:30:55 +020012680static struct snd_kcontrol_new alc268_base_mixer[] = {
12681 /* output mixer control */
12682 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12683 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12684 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12685 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012686 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12687 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12688 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012689 { }
12690};
12691
Takashi Iwai42171c12009-05-08 14:11:43 +020012692static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12693 /* output mixer control */
12694 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12695 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12696 ALC262_HIPPO_MASTER_SWITCH,
12697 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12698 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12699 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12700 { }
12701};
12702
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012703/* bind Beep switches of both NID 0x0f and 0x10 */
12704static struct hda_bind_ctls alc268_bind_beep_sw = {
12705 .ops = &snd_hda_bind_sw,
12706 .values = {
12707 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12708 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12709 0
12710 },
12711};
12712
12713static struct snd_kcontrol_new alc268_beep_mixer[] = {
12714 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12715 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12716 { }
12717};
12718
Kailang Yangd1a991a2007-08-15 16:21:59 +020012719static struct hda_verb alc268_eapd_verbs[] = {
12720 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12721 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12722 { }
12723};
12724
Takashi Iwaid2738092007-08-16 14:59:45 +020012725/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012726static struct hda_verb alc268_toshiba_verbs[] = {
12727 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12728 { } /* end */
12729};
12730
12731/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012732/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012733static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12734 .ops = &snd_hda_bind_vol,
12735 .values = {
12736 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12737 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12738 0
12739 },
12740};
12741
Takashi Iwai889c4392007-08-23 18:56:52 +020012742/* mute/unmute internal speaker according to the hp jack and mute state */
12743static void alc268_acer_automute(struct hda_codec *codec, int force)
12744{
12745 struct alc_spec *spec = codec->spec;
12746 unsigned int mute;
12747
12748 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012749 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012750 spec->sense_updated = 1;
12751 }
12752 if (spec->jack_present)
12753 mute = HDA_AMP_MUTE; /* mute internal speaker */
12754 else /* unmute internal speaker if necessary */
12755 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12756 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12757 HDA_AMP_MUTE, mute);
12758}
12759
12760
12761/* bind hp and internal speaker mute (with plug check) */
12762static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12763 struct snd_ctl_elem_value *ucontrol)
12764{
12765 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12766 long *valp = ucontrol->value.integer.value;
12767 int change;
12768
Takashi Iwai8de56b72009-07-24 16:51:47 +020012769 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012770 if (change)
12771 alc268_acer_automute(codec, 0);
12772 return change;
12773}
Takashi Iwaid2738092007-08-16 14:59:45 +020012774
Kailang Yang8ef355d2008-08-26 13:10:22 +020012775static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12776 /* output mixer control */
12777 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12778 {
12779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12780 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012781 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012782 .info = snd_hda_mixer_amp_switch_info,
12783 .get = snd_hda_mixer_amp_switch_get,
12784 .put = alc268_acer_master_sw_put,
12785 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12786 },
12787 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12788 { }
12789};
12790
Takashi Iwaid2738092007-08-16 14:59:45 +020012791static struct snd_kcontrol_new alc268_acer_mixer[] = {
12792 /* output mixer control */
12793 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12794 {
12795 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12796 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012797 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020012798 .info = snd_hda_mixer_amp_switch_info,
12799 .get = snd_hda_mixer_amp_switch_get,
12800 .put = alc268_acer_master_sw_put,
12801 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12802 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012803 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12804 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12805 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012806 { }
12807};
12808
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012809static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12810 /* output mixer control */
12811 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12812 {
12813 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12814 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012815 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012816 .info = snd_hda_mixer_amp_switch_info,
12817 .get = snd_hda_mixer_amp_switch_get,
12818 .put = alc268_acer_master_sw_put,
12819 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12820 },
12821 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12822 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12823 { }
12824};
12825
Kailang Yang8ef355d2008-08-26 13:10:22 +020012826static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12827 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12828 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12829 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12830 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12831 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12832 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12833 { }
12834};
12835
Takashi Iwaid2738092007-08-16 14:59:45 +020012836static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012837 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12838 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012839 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12840 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012841 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12842 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012843 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12844 { }
12845};
12846
12847/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012848#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012849#define alc268_toshiba_setup alc262_hippo_setup
12850#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012851
12852static void alc268_acer_unsol_event(struct hda_codec *codec,
12853 unsigned int res)
12854{
Takashi Iwai889c4392007-08-23 18:56:52 +020012855 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012856 return;
12857 alc268_acer_automute(codec, 1);
12858}
12859
Takashi Iwai889c4392007-08-23 18:56:52 +020012860static void alc268_acer_init_hook(struct hda_codec *codec)
12861{
12862 alc268_acer_automute(codec, 1);
12863}
12864
Kailang Yang8ef355d2008-08-26 13:10:22 +020012865/* toggle speaker-output according to the hp-jack state */
12866static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12867{
12868 unsigned int present;
12869 unsigned char bits;
12870
Wu Fengguang864f92b2009-11-18 12:38:02 +080012871 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012872 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012873 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012874 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012875 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012876 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012877}
12878
Kailang Yang8ef355d2008-08-26 13:10:22 +020012879static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12880 unsigned int res)
12881{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012882 switch (res >> 26) {
12883 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012884 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012885 break;
12886 case ALC880_MIC_EVENT:
12887 alc_mic_automute(codec);
12888 break;
12889 }
12890}
12891
12892static void alc268_acer_lc_setup(struct hda_codec *codec)
12893{
12894 struct alc_spec *spec = codec->spec;
12895 spec->ext_mic.pin = 0x18;
12896 spec->ext_mic.mux_idx = 0;
12897 spec->int_mic.pin = 0x12;
12898 spec->int_mic.mux_idx = 6;
12899 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012900}
12901
12902static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12903{
12904 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012905 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012906}
12907
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012908static struct snd_kcontrol_new alc268_dell_mixer[] = {
12909 /* output mixer control */
12910 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12911 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12912 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12913 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12914 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12915 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12916 { }
12917};
12918
12919static struct hda_verb alc268_dell_verbs[] = {
12920 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12921 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12922 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012923 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012924 { }
12925};
12926
12927/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012928static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012929{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012930 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012931
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012932 spec->autocfg.hp_pins[0] = 0x15;
12933 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012934 spec->ext_mic.pin = 0x18;
12935 spec->ext_mic.mux_idx = 0;
12936 spec->int_mic.pin = 0x19;
12937 spec->int_mic.mux_idx = 1;
12938 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012939}
12940
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012941static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12942 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12943 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12944 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12945 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12946 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12947 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12948 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12949 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12950 { }
12951};
12952
12953static struct hda_verb alc267_quanta_il1_verbs[] = {
12954 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12955 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12956 { }
12957};
12958
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012959static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012960{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012961 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012962 spec->autocfg.hp_pins[0] = 0x15;
12963 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012964 spec->ext_mic.pin = 0x18;
12965 spec->ext_mic.mux_idx = 0;
12966 spec->int_mic.pin = 0x19;
12967 spec->int_mic.mux_idx = 1;
12968 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012969}
12970
Kailang Yanga361d842007-06-05 12:30:55 +020012971/*
12972 * generic initialization of ADC, input mixers and output mixers
12973 */
12974static struct hda_verb alc268_base_init_verbs[] = {
12975 /* Unmute DAC0-1 and set vol = 0 */
12976 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012977 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012978
12979 /*
12980 * Set up output mixers (0x0c - 0x0e)
12981 */
12982 /* set vol=0 to output mixers */
12983 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012984 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12985
12986 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12987 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12988
12989 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12990 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12991 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12992 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12993 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12994 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12995 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12996 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12997
12998 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12999 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13000 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13001 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013002 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013003
13004 /* set PCBEEP vol = 0, mute connections */
13005 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13006 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13007 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013008
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013009 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013010
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013011 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13012 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13013 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13014 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013015
Kailang Yanga361d842007-06-05 12:30:55 +020013016 { }
13017};
13018
13019/*
13020 * generic initialization of ADC, input mixers and output mixers
13021 */
13022static struct hda_verb alc268_volume_init_verbs[] = {
13023 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013024 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13025 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013026
13027 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13028 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13029 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13030 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13031 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13032
Kailang Yanga361d842007-06-05 12:30:55 +020013033 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013034 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13035 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13036
13037 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013038 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013039
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013040 /* set PCBEEP vol = 0, mute connections */
13041 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13042 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13043 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013044
13045 { }
13046};
13047
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013048static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13049 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13050 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13051 { } /* end */
13052};
13053
Kailang Yanga361d842007-06-05 12:30:55 +020013054static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13055 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13056 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013057 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013058 { } /* end */
13059};
13060
13061static struct snd_kcontrol_new alc268_capture_mixer[] = {
13062 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13063 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13064 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13065 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013066 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013067 { } /* end */
13068};
13069
13070static struct hda_input_mux alc268_capture_source = {
13071 .num_items = 4,
13072 .items = {
13073 { "Mic", 0x0 },
13074 { "Front Mic", 0x1 },
13075 { "Line", 0x2 },
13076 { "CD", 0x3 },
13077 },
13078};
13079
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013080static struct hda_input_mux alc268_acer_capture_source = {
13081 .num_items = 3,
13082 .items = {
13083 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013084 { "Internal Mic", 0x1 },
13085 { "Line", 0x2 },
13086 },
13087};
13088
13089static struct hda_input_mux alc268_acer_dmic_capture_source = {
13090 .num_items = 3,
13091 .items = {
13092 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013093 { "Internal Mic", 0x6 },
13094 { "Line", 0x2 },
13095 },
13096};
13097
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013098#ifdef CONFIG_SND_DEBUG
13099static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013100 /* Volume widgets */
13101 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13102 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13103 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13104 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13105 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13106 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13107 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13108 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13109 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13110 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13111 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13112 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13113 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013114 /* The below appears problematic on some hardwares */
13115 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013116 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13117 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13118 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13119 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13120
13121 /* Modes for retasking pin widgets */
13122 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13123 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13124 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13125 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13126
13127 /* Controls for GPIO pins, assuming they are configured as outputs */
13128 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13129 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13130 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13131 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13132
13133 /* Switches to allow the digital SPDIF output pin to be enabled.
13134 * The ALC268 does not have an SPDIF input.
13135 */
13136 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13137
13138 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13139 * this output to turn on an external amplifier.
13140 */
13141 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13142 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13143
13144 { } /* end */
13145};
13146#endif
13147
Kailang Yanga361d842007-06-05 12:30:55 +020013148/* create input playback/capture controls for the given pin */
13149static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13150 const char *ctlname, int idx)
13151{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013152 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013153 int err;
13154
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013155 switch (nid) {
13156 case 0x14:
13157 case 0x16:
13158 dac = 0x02;
13159 break;
13160 case 0x15:
Takashi Iwai5d4abf92010-07-30 10:51:10 +020013161 case 0x1b:
Kailang Yang531d8792010-04-09 10:57:33 +020013162 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013163 dac = 0x03;
13164 break;
13165 default:
13166 return 0;
13167 }
13168 if (spec->multiout.dac_nids[0] != dac &&
13169 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013170 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013171 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013172 HDA_OUTPUT));
13173 if (err < 0)
13174 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013175 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13176 }
13177
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013178 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013179 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013180 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013181 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013182 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013183 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013184 if (err < 0)
13185 return err;
13186 return 0;
13187}
13188
13189/* add playback controls from the parsed DAC table */
13190static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13191 const struct auto_pin_cfg *cfg)
13192{
13193 hda_nid_t nid;
13194 int err;
13195
Kailang Yanga361d842007-06-05 12:30:55 +020013196 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013197
13198 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013199 if (nid) {
13200 const char *name;
13201 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13202 name = "Speaker";
13203 else
13204 name = "Front";
13205 err = alc268_new_analog_output(spec, nid, name, 0);
13206 if (err < 0)
13207 return err;
13208 }
Kailang Yanga361d842007-06-05 12:30:55 +020013209
13210 nid = cfg->speaker_pins[0];
13211 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013212 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013213 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13214 if (err < 0)
13215 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013216 } else {
13217 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13218 if (err < 0)
13219 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013220 }
13221 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013222 if (nid) {
13223 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13224 if (err < 0)
13225 return err;
13226 }
Kailang Yanga361d842007-06-05 12:30:55 +020013227
13228 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13229 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013230 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013231 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013232 if (err < 0)
13233 return err;
13234 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013235 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013236}
13237
13238/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013239static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013240 const struct auto_pin_cfg *cfg)
13241{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013242 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013243}
13244
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013245static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13246 hda_nid_t nid, int pin_type)
13247{
13248 int idx;
13249
13250 alc_set_pin_output(codec, nid, pin_type);
13251 if (nid == 0x14 || nid == 0x16)
13252 idx = 0;
13253 else
13254 idx = 1;
13255 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13256}
13257
13258static void alc268_auto_init_multi_out(struct hda_codec *codec)
13259{
13260 struct alc_spec *spec = codec->spec;
13261 hda_nid_t nid = spec->autocfg.line_out_pins[0];
13262 if (nid) {
13263 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13264 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13265 }
13266}
13267
13268static void alc268_auto_init_hp_out(struct hda_codec *codec)
13269{
13270 struct alc_spec *spec = codec->spec;
13271 hda_nid_t pin;
13272
13273 pin = spec->autocfg.hp_pins[0];
13274 if (pin)
13275 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
13276 pin = spec->autocfg.speaker_pins[0];
13277 if (pin)
13278 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
13279}
13280
Kailang Yanga361d842007-06-05 12:30:55 +020013281static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13282{
13283 struct alc_spec *spec = codec->spec;
13284 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13285 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13286 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13287 unsigned int dac_vol1, dac_vol2;
13288
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013289 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013290 snd_hda_codec_write(codec, speaker_nid, 0,
13291 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013292 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013293 snd_hda_codec_write(codec, 0x0f, 0,
13294 AC_VERB_SET_AMP_GAIN_MUTE,
13295 AMP_IN_UNMUTE(1));
13296 snd_hda_codec_write(codec, 0x10, 0,
13297 AC_VERB_SET_AMP_GAIN_MUTE,
13298 AMP_IN_UNMUTE(1));
13299 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013300 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013301 snd_hda_codec_write(codec, 0x0f, 0,
13302 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13303 snd_hda_codec_write(codec, 0x10, 0,
13304 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13305 }
13306
13307 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013308 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013309 dac_vol2 = AMP_OUT_ZERO;
13310 else if (line_nid == 0x15)
13311 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013312 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013313 dac_vol2 = AMP_OUT_ZERO;
13314 else if (hp_nid == 0x15)
13315 dac_vol1 = AMP_OUT_ZERO;
13316 if (line_nid != 0x16 || hp_nid != 0x16 ||
13317 spec->autocfg.line_out_pins[1] != 0x16 ||
13318 spec->autocfg.line_out_pins[2] != 0x16)
13319 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13320
13321 snd_hda_codec_write(codec, 0x02, 0,
13322 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13323 snd_hda_codec_write(codec, 0x03, 0,
13324 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13325}
13326
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013327/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013328#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13329#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013330#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013331#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13332
13333/*
13334 * BIOS auto configuration
13335 */
13336static int alc268_parse_auto_config(struct hda_codec *codec)
13337{
13338 struct alc_spec *spec = codec->spec;
13339 int err;
13340 static hda_nid_t alc268_ignore[] = { 0 };
13341
13342 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13343 alc268_ignore);
13344 if (err < 0)
13345 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013346 if (!spec->autocfg.line_outs) {
13347 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13348 spec->multiout.max_channels = 2;
13349 spec->no_analog = 1;
13350 goto dig_only;
13351 }
Kailang Yanga361d842007-06-05 12:30:55 +020013352 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013353 }
Kailang Yanga361d842007-06-05 12:30:55 +020013354 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13355 if (err < 0)
13356 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013357 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013358 if (err < 0)
13359 return err;
13360
13361 spec->multiout.max_channels = 2;
13362
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013363 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013364 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013365 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013366 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013367 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013368
Takashi Iwai892981f2009-03-02 08:04:35 +010013369 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013370 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013371
Takashi Iwaid88897e2008-10-31 15:01:37 +010013372 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013373 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013374 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013375
Takashi Iwai776e1842007-08-29 15:07:11 +020013376 err = alc_auto_add_mic_boost(codec);
13377 if (err < 0)
13378 return err;
13379
Kailang Yang6227cdc2010-02-25 08:36:52 +010013380 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013381
Kailang Yanga361d842007-06-05 12:30:55 +020013382 return 1;
13383}
13384
Kailang Yanga361d842007-06-05 12:30:55 +020013385#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13386
13387/* init callback for auto-configuration model -- overriding the default init */
13388static void alc268_auto_init(struct hda_codec *codec)
13389{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013390 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013391 alc268_auto_init_multi_out(codec);
13392 alc268_auto_init_hp_out(codec);
13393 alc268_auto_init_mono_speaker_out(codec);
13394 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013395 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013396 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013397 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013398}
13399
13400/*
13401 * configuration and preset
13402 */
13403static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013404 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013405 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013406 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013407 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013408 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013409 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013410 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013411 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013412#ifdef CONFIG_SND_DEBUG
13413 [ALC268_TEST] = "test",
13414#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013415 [ALC268_AUTO] = "auto",
13416};
13417
13418static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013419 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013420 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013421 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013422 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013423 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013424 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13425 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013426 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013427 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13428 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013429 /* almost compatible with toshiba but with optional digital outs;
13430 * auto-probing seems working fine
13431 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013432 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013433 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013434 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013435 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013436 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013437 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013438 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013439 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020013440 {}
13441};
13442
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013443/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13444static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13445 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13446 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13447 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13448 ALC268_TOSHIBA),
13449 {}
13450};
13451
Kailang Yanga361d842007-06-05 12:30:55 +020013452static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013453 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013454 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13455 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013456 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13457 alc267_quanta_il1_verbs },
13458 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13459 .dac_nids = alc268_dac_nids,
13460 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13461 .adc_nids = alc268_adc_nids_alt,
13462 .hp_nid = 0x03,
13463 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13464 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013465 .unsol_event = alc_sku_unsol_event,
13466 .setup = alc267_quanta_il1_setup,
13467 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013468 },
Kailang Yanga361d842007-06-05 12:30:55 +020013469 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013470 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13471 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013472 .init_verbs = { alc268_base_init_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,
Takashi Iwaie1406342008-02-11 18:32:32 +010013477 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013478 .hp_nid = 0x03,
13479 .dig_out_nid = ALC268_DIGOUT_NID,
13480 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13481 .channel_mode = alc268_modes,
13482 .input_mux = &alc268_capture_source,
13483 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013484 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013485 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013486 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013487 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13488 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013489 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13490 .dac_nids = alc268_dac_nids,
13491 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13492 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013493 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013494 .hp_nid = 0x03,
13495 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13496 .channel_mode = alc268_modes,
13497 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013498 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013499 .setup = alc268_toshiba_setup,
13500 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013501 },
13502 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013503 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013504 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013505 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13506 alc268_acer_verbs },
13507 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13508 .dac_nids = alc268_dac_nids,
13509 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13510 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013511 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013512 .hp_nid = 0x02,
13513 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13514 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013515 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013516 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013517 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013518 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013519 [ALC268_ACER_DMIC] = {
13520 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13521 alc268_beep_mixer },
13522 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13523 alc268_acer_verbs },
13524 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13525 .dac_nids = alc268_dac_nids,
13526 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13527 .adc_nids = alc268_adc_nids_alt,
13528 .capsrc_nids = alc268_capsrc_nids,
13529 .hp_nid = 0x02,
13530 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13531 .channel_mode = alc268_modes,
13532 .input_mux = &alc268_acer_dmic_capture_source,
13533 .unsol_event = alc268_acer_unsol_event,
13534 .init_hook = alc268_acer_init_hook,
13535 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013536 [ALC268_ACER_ASPIRE_ONE] = {
13537 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013538 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013539 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013540 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13541 alc268_acer_aspire_one_verbs },
13542 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13543 .dac_nids = alc268_dac_nids,
13544 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13545 .adc_nids = alc268_adc_nids_alt,
13546 .capsrc_nids = alc268_capsrc_nids,
13547 .hp_nid = 0x03,
13548 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13549 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013550 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013551 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013552 .init_hook = alc268_acer_lc_init_hook,
13553 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013554 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013555 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13556 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013557 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13558 alc268_dell_verbs },
13559 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13560 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013561 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13562 .adc_nids = alc268_adc_nids_alt,
13563 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013564 .hp_nid = 0x02,
13565 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13566 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013567 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013568 .setup = alc268_dell_setup,
13569 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013570 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013571 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013572 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13573 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013574 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13575 alc268_toshiba_verbs },
13576 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13577 .dac_nids = alc268_dac_nids,
13578 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13579 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013580 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013581 .hp_nid = 0x03,
13582 .dig_out_nid = ALC268_DIGOUT_NID,
13583 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13584 .channel_mode = alc268_modes,
13585 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013586 .setup = alc268_toshiba_setup,
13587 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013588 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013589#ifdef CONFIG_SND_DEBUG
13590 [ALC268_TEST] = {
13591 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13592 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13593 alc268_volume_init_verbs },
13594 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13595 .dac_nids = alc268_dac_nids,
13596 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13597 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013598 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013599 .hp_nid = 0x03,
13600 .dig_out_nid = ALC268_DIGOUT_NID,
13601 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13602 .channel_mode = alc268_modes,
13603 .input_mux = &alc268_capture_source,
13604 },
13605#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013606};
13607
13608static int patch_alc268(struct hda_codec *codec)
13609{
13610 struct alc_spec *spec;
13611 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013612 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013613
Julia Lawallef86f582009-12-19 08:18:03 +010013614 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013615 if (spec == NULL)
13616 return -ENOMEM;
13617
13618 codec->spec = spec;
13619
13620 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13621 alc268_models,
13622 alc268_cfg_tbl);
13623
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013624 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13625 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013626 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013627
Kailang Yanga361d842007-06-05 12:30:55 +020013628 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013629 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13630 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013631 board_config = ALC268_AUTO;
13632 }
13633
13634 if (board_config == ALC268_AUTO) {
13635 /* automatic parse from the BIOS config */
13636 err = alc268_parse_auto_config(codec);
13637 if (err < 0) {
13638 alc_free(codec);
13639 return err;
13640 } else if (!err) {
13641 printk(KERN_INFO
13642 "hda_codec: Cannot set up configuration "
13643 "from BIOS. Using base mode...\n");
13644 board_config = ALC268_3ST;
13645 }
13646 }
13647
13648 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013649 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013650
Kailang Yanga361d842007-06-05 12:30:55 +020013651 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13652 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013653 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013654
Kailang Yanga361d842007-06-05 12:30:55 +020013655 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13656
Takashi Iwai22971e32009-02-10 11:56:44 +010013657 has_beep = 0;
13658 for (i = 0; i < spec->num_mixers; i++) {
13659 if (spec->mixers[i] == alc268_beep_mixer) {
13660 has_beep = 1;
13661 break;
13662 }
13663 }
13664
13665 if (has_beep) {
13666 err = snd_hda_attach_beep_device(codec, 0x1);
13667 if (err < 0) {
13668 alc_free(codec);
13669 return err;
13670 }
13671 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13672 /* override the amp caps for beep generator */
13673 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013674 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13675 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13676 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13677 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013678 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013679
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013680 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013681 /* check whether NID 0x07 is valid */
13682 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013683 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013684
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013685 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013686 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013687 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013688 if (spec->auto_mic ||
13689 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013690 spec->adc_nids = alc268_adc_nids_alt;
13691 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013692 if (spec->auto_mic)
13693 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013694 if (spec->auto_mic || spec->input_mux->num_items == 1)
13695 add_mixer(spec, alc268_capture_nosrc_mixer);
13696 else
13697 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013698 } else {
13699 spec->adc_nids = alc268_adc_nids;
13700 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013701 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013702 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013703 /* set default input source */
13704 for (i = 0; i < spec->num_adc_nids; i++)
13705 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13706 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013707 i < spec->num_mux_defs ?
13708 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013709 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013710 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013711
13712 spec->vmaster_nid = 0x02;
13713
Kailang Yanga361d842007-06-05 12:30:55 +020013714 codec->patch_ops = alc_patch_ops;
13715 if (board_config == ALC268_AUTO)
13716 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013717
Kailang Yanga361d842007-06-05 12:30:55 +020013718 return 0;
13719}
13720
13721/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013722 * ALC269 channel source setting (2 channel)
13723 */
13724#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13725
13726#define alc269_dac_nids alc260_dac_nids
13727
13728static hda_nid_t alc269_adc_nids[1] = {
13729 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013730 0x08,
13731};
13732
Takashi Iwaie01bf502008-08-21 16:25:07 +020013733static hda_nid_t alc269_capsrc_nids[1] = {
13734 0x23,
13735};
13736
Kailang Yang84898e82010-02-04 14:16:14 +010013737static hda_nid_t alc269vb_adc_nids[1] = {
13738 /* ADC1 */
13739 0x09,
13740};
13741
13742static hda_nid_t alc269vb_capsrc_nids[1] = {
13743 0x22,
13744};
13745
Takashi Iwai66946352010-03-29 17:21:45 +020013746static hda_nid_t alc269_adc_candidates[] = {
13747 0x08, 0x09, 0x07,
13748};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013749
Kailang Yangf6a92242007-12-13 16:52:54 +010013750#define alc269_modes alc260_modes
13751#define alc269_capture_source alc880_lg_lw_capture_source
13752
13753static struct snd_kcontrol_new alc269_base_mixer[] = {
13754 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13755 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13756 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13757 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13758 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13759 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13760 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13761 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13762 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13763 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13764 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13765 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13766 { } /* end */
13767};
13768
Kailang Yang60db6b52008-08-26 13:13:00 +020013769static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13770 /* output mixer control */
13771 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13772 {
13773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13774 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013775 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013776 .info = snd_hda_mixer_amp_switch_info,
13777 .get = snd_hda_mixer_amp_switch_get,
13778 .put = alc268_acer_master_sw_put,
13779 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13780 },
13781 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13782 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13783 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13784 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13785 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13786 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013787 { }
13788};
13789
Tony Vroon64154832008-11-06 15:08:49 +000013790static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13791 /* output mixer control */
13792 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13793 {
13794 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13795 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013796 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013797 .info = snd_hda_mixer_amp_switch_info,
13798 .get = snd_hda_mixer_amp_switch_get,
13799 .put = alc268_acer_master_sw_put,
13800 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13801 },
13802 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13803 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13804 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13805 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13806 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13807 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13808 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13809 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13810 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013811 { }
13812};
13813
Kailang Yang84898e82010-02-04 14:16:14 +010013814static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013815 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013816 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013817 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013818 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013819 { } /* end */
13820};
13821
Kailang Yang84898e82010-02-04 14:16:14 +010013822static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
13823 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13824 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13825 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13826 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13827 { } /* end */
13828};
13829
Kailang Yangf6a92242007-12-13 16:52:54 +010013830/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010013831static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
13832 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13833 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13834 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13835 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13836 { } /* end */
13837};
13838
13839static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013840 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13841 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013842 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13843 { } /* end */
13844};
13845
Kailang Yang84898e82010-02-04 14:16:14 +010013846static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
13847 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13848 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13849 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13850 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13851 { } /* end */
13852};
13853
13854static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
13855 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13856 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13857 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13858 { } /* end */
13859};
13860
Takashi Iwai26f5df22008-11-03 17:39:46 +010013861/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013862#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013863
Kailang Yang60db6b52008-08-26 13:13:00 +020013864static struct hda_verb alc269_quanta_fl1_verbs[] = {
13865 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13866 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13867 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13868 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13869 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13870 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13871 { }
13872};
13873
Tony Vroon64154832008-11-06 15:08:49 +000013874static struct hda_verb alc269_lifebook_verbs[] = {
13875 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13876 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13877 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13878 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13879 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13880 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13881 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13882 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13883 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13884 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13885 { }
13886};
13887
Kailang Yang60db6b52008-08-26 13:13:00 +020013888/* toggle speaker-output according to the hp-jack state */
13889static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13890{
13891 unsigned int present;
13892 unsigned char bits;
13893
Wu Fengguang864f92b2009-11-18 12:38:02 +080013894 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013895 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020013896 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013897 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013898 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013899 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013900
13901 snd_hda_codec_write(codec, 0x20, 0,
13902 AC_VERB_SET_COEF_INDEX, 0x0c);
13903 snd_hda_codec_write(codec, 0x20, 0,
13904 AC_VERB_SET_PROC_COEF, 0x680);
13905
13906 snd_hda_codec_write(codec, 0x20, 0,
13907 AC_VERB_SET_COEF_INDEX, 0x0c);
13908 snd_hda_codec_write(codec, 0x20, 0,
13909 AC_VERB_SET_PROC_COEF, 0x480);
13910}
13911
Tony Vroon64154832008-11-06 15:08:49 +000013912/* toggle speaker-output according to the hp-jacks state */
13913static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13914{
13915 unsigned int present;
13916 unsigned char bits;
13917
13918 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013919 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013920
13921 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013922 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013923
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013924 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000013925 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013926 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013927 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013928 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013929
13930 snd_hda_codec_write(codec, 0x20, 0,
13931 AC_VERB_SET_COEF_INDEX, 0x0c);
13932 snd_hda_codec_write(codec, 0x20, 0,
13933 AC_VERB_SET_PROC_COEF, 0x680);
13934
13935 snd_hda_codec_write(codec, 0x20, 0,
13936 AC_VERB_SET_COEF_INDEX, 0x0c);
13937 snd_hda_codec_write(codec, 0x20, 0,
13938 AC_VERB_SET_PROC_COEF, 0x480);
13939}
13940
Tony Vroon64154832008-11-06 15:08:49 +000013941static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13942{
13943 unsigned int present_laptop;
13944 unsigned int present_dock;
13945
Wu Fengguang864f92b2009-11-18 12:38:02 +080013946 present_laptop = snd_hda_jack_detect(codec, 0x18);
13947 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013948
13949 /* Laptop mic port overrides dock mic port, design decision */
13950 if (present_dock)
13951 snd_hda_codec_write(codec, 0x23, 0,
13952 AC_VERB_SET_CONNECT_SEL, 0x3);
13953 if (present_laptop)
13954 snd_hda_codec_write(codec, 0x23, 0,
13955 AC_VERB_SET_CONNECT_SEL, 0x0);
13956 if (!present_dock && !present_laptop)
13957 snd_hda_codec_write(codec, 0x23, 0,
13958 AC_VERB_SET_CONNECT_SEL, 0x1);
13959}
13960
Kailang Yang60db6b52008-08-26 13:13:00 +020013961static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13962 unsigned int res)
13963{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013964 switch (res >> 26) {
13965 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013966 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013967 break;
13968 case ALC880_MIC_EVENT:
13969 alc_mic_automute(codec);
13970 break;
13971 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013972}
13973
Tony Vroon64154832008-11-06 15:08:49 +000013974static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13975 unsigned int res)
13976{
13977 if ((res >> 26) == ALC880_HP_EVENT)
13978 alc269_lifebook_speaker_automute(codec);
13979 if ((res >> 26) == ALC880_MIC_EVENT)
13980 alc269_lifebook_mic_autoswitch(codec);
13981}
13982
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013983static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13984{
13985 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013986 spec->autocfg.hp_pins[0] = 0x15;
13987 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013988 spec->ext_mic.pin = 0x18;
13989 spec->ext_mic.mux_idx = 0;
13990 spec->int_mic.pin = 0x19;
13991 spec->int_mic.mux_idx = 1;
13992 spec->auto_mic = 1;
13993}
13994
Kailang Yang60db6b52008-08-26 13:13:00 +020013995static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13996{
13997 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013998 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013999}
14000
Tony Vroon64154832008-11-06 15:08:49 +000014001static void alc269_lifebook_init_hook(struct hda_codec *codec)
14002{
14003 alc269_lifebook_speaker_automute(codec);
14004 alc269_lifebook_mic_autoswitch(codec);
14005}
14006
Kailang Yang84898e82010-02-04 14:16:14 +010014007static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014008 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14009 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14010 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14011 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14012 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14013 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14014 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14015 {}
14016};
14017
Kailang Yang84898e82010-02-04 14:16:14 +010014018static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014019 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14020 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14021 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14022 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14023 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14024 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14025 {}
14026};
14027
Kailang Yang84898e82010-02-04 14:16:14 +010014028static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14029 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14030 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14031 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14032 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14033 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14034 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14035 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14036 {}
14037};
14038
14039static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14040 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14041 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14042 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14043 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14044 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14045 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14046 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14047 {}
14048};
14049
Kailang Yang60db6b52008-08-26 13:13:00 +020014050/* toggle speaker-output according to the hp-jack state */
14051static void alc269_speaker_automute(struct hda_codec *codec)
14052{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014053 struct alc_spec *spec = codec->spec;
14054 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014055 unsigned int present;
14056 unsigned char bits;
14057
Kailang Yangebb83ee2009-12-17 12:23:00 +010014058 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014059 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014060 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014061 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014062 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014063 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014064}
14065
Kailang Yang60db6b52008-08-26 13:13:00 +020014066/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014067static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014068 unsigned int res)
14069{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014070 switch (res >> 26) {
14071 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014072 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014073 break;
14074 case ALC880_MIC_EVENT:
14075 alc_mic_automute(codec);
14076 break;
14077 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014078}
14079
Kailang Yang226b1ec2010-04-09 11:01:20 +020014080static void alc269_laptop_amic_setup(struct hda_codec *codec)
14081{
14082 struct alc_spec *spec = codec->spec;
14083 spec->autocfg.hp_pins[0] = 0x15;
14084 spec->autocfg.speaker_pins[0] = 0x14;
14085 spec->ext_mic.pin = 0x18;
14086 spec->ext_mic.mux_idx = 0;
14087 spec->int_mic.pin = 0x19;
14088 spec->int_mic.mux_idx = 1;
14089 spec->auto_mic = 1;
14090}
14091
Kailang Yang84898e82010-02-04 14:16:14 +010014092static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014093{
14094 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014095 spec->autocfg.hp_pins[0] = 0x15;
14096 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014097 spec->ext_mic.pin = 0x18;
14098 spec->ext_mic.mux_idx = 0;
14099 spec->int_mic.pin = 0x12;
14100 spec->int_mic.mux_idx = 5;
14101 spec->auto_mic = 1;
14102}
14103
Kailang Yang226b1ec2010-04-09 11:01:20 +020014104static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014105{
14106 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014107 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014108 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014109 spec->ext_mic.pin = 0x18;
14110 spec->ext_mic.mux_idx = 0;
14111 spec->int_mic.pin = 0x19;
14112 spec->int_mic.mux_idx = 1;
14113 spec->auto_mic = 1;
14114}
14115
Kailang Yang226b1ec2010-04-09 11:01:20 +020014116static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14117{
14118 struct alc_spec *spec = codec->spec;
14119 spec->autocfg.hp_pins[0] = 0x21;
14120 spec->autocfg.speaker_pins[0] = 0x14;
14121 spec->ext_mic.pin = 0x18;
14122 spec->ext_mic.mux_idx = 0;
14123 spec->int_mic.pin = 0x12;
14124 spec->int_mic.mux_idx = 6;
14125 spec->auto_mic = 1;
14126}
14127
Kailang Yang84898e82010-02-04 14:16:14 +010014128static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014129{
14130 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014131 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014132}
14133
Kailang Yangf6a92242007-12-13 16:52:54 +010014134/*
14135 * generic initialization of ADC, input mixers and output mixers
14136 */
14137static struct hda_verb alc269_init_verbs[] = {
14138 /*
14139 * Unmute ADC0 and set the default input to mic-in
14140 */
Kailang Yang84898e82010-02-04 14:16:14 +010014141 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014142
14143 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014144 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014145 */
14146 /* set vol=0 to output mixers */
14147 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14148 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14149
14150 /* set up input amps for analog loopback */
14151 /* Amp Indices: DAC = 0, mixer = 1 */
14152 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14153 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14154 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14155 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14156 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14157 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14158
14159 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14160 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14161 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14162 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14163 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14164 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14165 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14166
14167 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14168 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014169
Kailang Yang84898e82010-02-04 14:16:14 +010014170 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014171 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14172 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014173 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014174
14175 /* set EAPD */
14176 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014177 { }
14178};
14179
14180static struct hda_verb alc269vb_init_verbs[] = {
14181 /*
14182 * Unmute ADC0 and set the default input to mic-in
14183 */
14184 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14185
14186 /*
14187 * Set up output mixers (0x02 - 0x03)
14188 */
14189 /* set vol=0 to output mixers */
14190 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14191 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14192
14193 /* set up input amps for analog loopback */
14194 /* Amp Indices: DAC = 0, mixer = 1 */
14195 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14196 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14197 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14198 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14199 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14200 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14201
14202 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14203 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14204 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14205 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14206 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14207 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14208 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14209
14210 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14211 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14212
14213 /* FIXME: use Mux-type input source selection */
14214 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14215 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14216 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14217
14218 /* set EAPD */
14219 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014220 { }
14221};
14222
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014223#define alc269_auto_create_multi_out_ctls \
14224 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014225#define alc269_auto_create_input_ctls \
14226 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014227
14228#ifdef CONFIG_SND_HDA_POWER_SAVE
14229#define alc269_loopbacks alc880_loopbacks
14230#endif
14231
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014232/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014233#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14234#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14235#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14236#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14237
Takashi Iwaif03d3112009-03-05 14:18:16 +010014238static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14239 .substreams = 1,
14240 .channels_min = 2,
14241 .channels_max = 8,
14242 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14243 /* NID is set in alc_build_pcms */
14244 .ops = {
14245 .open = alc880_playback_pcm_open,
14246 .prepare = alc880_playback_pcm_prepare,
14247 .cleanup = alc880_playback_pcm_cleanup
14248 },
14249};
14250
14251static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14252 .substreams = 1,
14253 .channels_min = 2,
14254 .channels_max = 2,
14255 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14256 /* NID is set in alc_build_pcms */
14257};
14258
Takashi Iwaiad358792010-03-30 18:00:59 +020014259#ifdef CONFIG_SND_HDA_POWER_SAVE
14260static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14261{
14262 switch (codec->subsystem_id) {
14263 case 0x103c1586:
14264 return 1;
14265 }
14266 return 0;
14267}
14268
14269static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14270{
14271 /* update mute-LED according to the speaker mute state */
14272 if (nid == 0x01 || nid == 0x14) {
14273 int pinval;
14274 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14275 HDA_AMP_MUTE)
14276 pinval = 0x24;
14277 else
14278 pinval = 0x20;
14279 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014280 snd_hda_codec_update_cache(codec, 0x19, 0,
14281 AC_VERB_SET_PIN_WIDGET_CONTROL,
14282 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014283 }
14284 return alc_check_power_status(codec, nid);
14285}
14286#endif /* CONFIG_SND_HDA_POWER_SAVE */
14287
Takashi Iwai840b64c2010-07-13 22:49:01 +020014288static int alc275_setup_dual_adc(struct hda_codec *codec)
14289{
14290 struct alc_spec *spec = codec->spec;
14291
14292 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14293 return 0;
14294 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14295 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14296 if (spec->ext_mic.pin <= 0x12) {
14297 spec->private_adc_nids[0] = 0x08;
14298 spec->private_adc_nids[1] = 0x11;
14299 spec->private_capsrc_nids[0] = 0x23;
14300 spec->private_capsrc_nids[1] = 0x22;
14301 } else {
14302 spec->private_adc_nids[0] = 0x11;
14303 spec->private_adc_nids[1] = 0x08;
14304 spec->private_capsrc_nids[0] = 0x22;
14305 spec->private_capsrc_nids[1] = 0x23;
14306 }
14307 spec->adc_nids = spec->private_adc_nids;
14308 spec->capsrc_nids = spec->private_capsrc_nids;
14309 spec->num_adc_nids = 2;
14310 spec->dual_adc_switch = 1;
14311 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14312 spec->adc_nids[0], spec->adc_nids[1]);
14313 return 1;
14314 }
14315 return 0;
14316}
14317
Kailang Yangf6a92242007-12-13 16:52:54 +010014318/*
14319 * BIOS auto configuration
14320 */
14321static int alc269_parse_auto_config(struct hda_codec *codec)
14322{
14323 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014324 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014325 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14326
14327 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14328 alc269_ignore);
14329 if (err < 0)
14330 return err;
14331
14332 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14333 if (err < 0)
14334 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014335 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010014336 if (err < 0)
14337 return err;
14338
14339 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14340
Takashi Iwai757899a2010-07-30 10:48:14 +020014341 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014342
Takashi Iwai603c4012008-07-30 15:01:44 +020014343 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014344 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014345
Kailang Yang84898e82010-02-04 14:16:14 +010014346 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
14347 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014348 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014349 } else {
14350 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014351 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014352 }
14353
Kailang Yangf6a92242007-12-13 16:52:54 +010014354 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014355 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014356
14357 if (!alc275_setup_dual_adc(codec))
14358 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14359 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014360
Takashi Iwaie01bf502008-08-21 16:25:07 +020014361 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014362 if (!spec->dual_adc_switch)
14363 snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
Takashi Iwaie01bf502008-08-21 16:25:07 +020014364 0, AC_VERB_SET_CONNECT_SEL,
14365 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014366
14367 err = alc_auto_add_mic_boost(codec);
14368 if (err < 0)
14369 return err;
14370
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014371 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014372 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014373
Kailang Yangf6a92242007-12-13 16:52:54 +010014374 return 1;
14375}
14376
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014377#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14378#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014379#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14380
14381
14382/* init callback for auto-configuration model -- overriding the default init */
14383static void alc269_auto_init(struct hda_codec *codec)
14384{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014385 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014386 alc269_auto_init_multi_out(codec);
14387 alc269_auto_init_hp_out(codec);
14388 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014389 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014390 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014391 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014392}
14393
Takashi Iwaiff818c22010-04-12 08:59:25 +020014394enum {
14395 ALC269_FIXUP_SONY_VAIO,
14396};
14397
Tobias Klauserfbc25662010-05-20 10:40:55 +020014398static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
Takashi Iwaiff818c22010-04-12 08:59:25 +020014399 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14400 {}
14401};
14402
14403static const struct alc_fixup alc269_fixups[] = {
14404 [ALC269_FIXUP_SONY_VAIO] = {
14405 .verbs = alc269_sony_vaio_fixup_verbs
14406 },
14407};
14408
14409static struct snd_pci_quirk alc269_fixup_tbl[] = {
14410 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
14411 {}
14412};
14413
14414
Kailang Yangf6a92242007-12-13 16:52:54 +010014415/*
14416 * configuration and preset
14417 */
14418static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014419 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014420 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014421 [ALC269_AMIC] = "laptop-amic",
14422 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014423 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014424 [ALC269_LIFEBOOK] = "lifebook",
14425 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014426};
14427
14428static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014429 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020014430 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014431 ALC269_AMIC),
14432 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14433 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14434 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14435 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14436 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14437 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14438 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14439 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14440 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14441 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14442 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14443 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14444 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14445 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14446 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14447 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14448 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14449 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14450 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14451 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14452 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14453 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14454 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14455 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14456 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14457 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14458 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14459 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14460 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14461 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14462 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14463 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14464 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14465 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14466 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14467 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014468 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014469 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014470 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014471 ALC269_DMIC),
14472 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14473 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014474 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014475 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014476 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14477 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14478 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14479 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14480 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14481 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014482 {}
14483};
14484
14485static struct alc_config_preset alc269_presets[] = {
14486 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014487 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014488 .init_verbs = { alc269_init_verbs },
14489 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14490 .dac_nids = alc269_dac_nids,
14491 .hp_nid = 0x03,
14492 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14493 .channel_mode = alc269_modes,
14494 .input_mux = &alc269_capture_source,
14495 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014496 [ALC269_QUANTA_FL1] = {
14497 .mixers = { alc269_quanta_fl1_mixer },
14498 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14499 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14500 .dac_nids = alc269_dac_nids,
14501 .hp_nid = 0x03,
14502 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14503 .channel_mode = alc269_modes,
14504 .input_mux = &alc269_capture_source,
14505 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014506 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014507 .init_hook = alc269_quanta_fl1_init_hook,
14508 },
Kailang Yang84898e82010-02-04 14:16:14 +010014509 [ALC269_AMIC] = {
14510 .mixers = { alc269_laptop_mixer },
14511 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014512 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014513 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014514 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14515 .dac_nids = alc269_dac_nids,
14516 .hp_nid = 0x03,
14517 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14518 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014519 .unsol_event = alc269_laptop_unsol_event,
14520 .setup = alc269_laptop_amic_setup,
14521 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014522 },
Kailang Yang84898e82010-02-04 14:16:14 +010014523 [ALC269_DMIC] = {
14524 .mixers = { alc269_laptop_mixer },
14525 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014526 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014527 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014528 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14529 .dac_nids = alc269_dac_nids,
14530 .hp_nid = 0x03,
14531 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14532 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014533 .unsol_event = alc269_laptop_unsol_event,
14534 .setup = alc269_laptop_dmic_setup,
14535 .init_hook = alc269_laptop_inithook,
14536 },
14537 [ALC269VB_AMIC] = {
14538 .mixers = { alc269vb_laptop_mixer },
14539 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14540 .init_verbs = { alc269vb_init_verbs,
14541 alc269vb_laptop_amic_init_verbs },
14542 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14543 .dac_nids = alc269_dac_nids,
14544 .hp_nid = 0x03,
14545 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14546 .channel_mode = alc269_modes,
14547 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014548 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014549 .init_hook = alc269_laptop_inithook,
14550 },
14551 [ALC269VB_DMIC] = {
14552 .mixers = { alc269vb_laptop_mixer },
14553 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14554 .init_verbs = { alc269vb_init_verbs,
14555 alc269vb_laptop_dmic_init_verbs },
14556 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14557 .dac_nids = alc269_dac_nids,
14558 .hp_nid = 0x03,
14559 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14560 .channel_mode = alc269_modes,
14561 .unsol_event = alc269_laptop_unsol_event,
14562 .setup = alc269vb_laptop_dmic_setup,
14563 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014564 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014565 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014566 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014567 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014568 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014569 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014570 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14571 .dac_nids = alc269_dac_nids,
14572 .hp_nid = 0x03,
14573 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14574 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014575 .unsol_event = alc269_laptop_unsol_event,
14576 .setup = alc269_laptop_dmic_setup,
14577 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014578 },
Tony Vroon64154832008-11-06 15:08:49 +000014579 [ALC269_LIFEBOOK] = {
14580 .mixers = { alc269_lifebook_mixer },
14581 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14582 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14583 .dac_nids = alc269_dac_nids,
14584 .hp_nid = 0x03,
14585 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14586 .channel_mode = alc269_modes,
14587 .input_mux = &alc269_capture_source,
14588 .unsol_event = alc269_lifebook_unsol_event,
14589 .init_hook = alc269_lifebook_init_hook,
14590 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014591};
14592
14593static int patch_alc269(struct hda_codec *codec)
14594{
14595 struct alc_spec *spec;
14596 int board_config;
14597 int err;
Kailang Yang84898e82010-02-04 14:16:14 +010014598 int is_alc269vb = 0;
Kailang Yangf6a92242007-12-13 16:52:54 +010014599
14600 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14601 if (spec == NULL)
14602 return -ENOMEM;
14603
14604 codec->spec = spec;
14605
Kailang Yangda00c242010-03-19 11:23:45 +010014606 alc_auto_parse_customize_define(codec);
14607
Kailang Yang274693f2009-12-03 10:07:50 +010014608 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014609 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14610 spec->cdefine.platform_type == 1)
14611 alc_codec_rename(codec, "ALC271X");
14612 else
14613 alc_codec_rename(codec, "ALC259");
Kailang Yang84898e82010-02-04 14:16:14 +010014614 is_alc269vb = 1;
Kailang Yangc027ddc2010-03-19 11:33:06 +010014615 } else
14616 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010014617
Kailang Yangf6a92242007-12-13 16:52:54 +010014618 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14619 alc269_models,
14620 alc269_cfg_tbl);
14621
14622 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014623 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14624 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014625 board_config = ALC269_AUTO;
14626 }
14627
Takashi Iwaiff818c22010-04-12 08:59:25 +020014628 if (board_config == ALC269_AUTO)
14629 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
14630
Kailang Yangf6a92242007-12-13 16:52:54 +010014631 if (board_config == ALC269_AUTO) {
14632 /* automatic parse from the BIOS config */
14633 err = alc269_parse_auto_config(codec);
14634 if (err < 0) {
14635 alc_free(codec);
14636 return err;
14637 } else if (!err) {
14638 printk(KERN_INFO
14639 "hda_codec: Cannot set up configuration "
14640 "from BIOS. Using base mode...\n");
14641 board_config = ALC269_BASIC;
14642 }
14643 }
14644
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014645 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014646 err = snd_hda_attach_beep_device(codec, 0x1);
14647 if (err < 0) {
14648 alc_free(codec);
14649 return err;
14650 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014651 }
14652
Kailang Yangf6a92242007-12-13 16:52:54 +010014653 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014654 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014655
Kailang Yang84898e82010-02-04 14:16:14 +010014656 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014657 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14658 * fix the sample rate of analog I/O to 44.1kHz
14659 */
14660 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14661 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020014662 } else if (spec->dual_adc_switch) {
14663 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14664 /* switch ADC dynamically */
14665 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014666 } else {
14667 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14668 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14669 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014670 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14671 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14672
Takashi Iwai66946352010-03-29 17:21:45 +020014673 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
14674 if (!is_alc269vb) {
14675 spec->adc_nids = alc269_adc_nids;
14676 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14677 spec->capsrc_nids = alc269_capsrc_nids;
14678 } else {
14679 spec->adc_nids = alc269vb_adc_nids;
14680 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14681 spec->capsrc_nids = alc269vb_capsrc_nids;
14682 }
Kailang Yang84898e82010-02-04 14:16:14 +010014683 }
14684
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014685 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014686 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014687 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014688 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014689
Takashi Iwaiff818c22010-04-12 08:59:25 +020014690 if (board_config == ALC269_AUTO)
14691 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
14692
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014693 spec->vmaster_nid = 0x02;
14694
Kailang Yangf6a92242007-12-13 16:52:54 +010014695 codec->patch_ops = alc_patch_ops;
14696 if (board_config == ALC269_AUTO)
14697 spec->init_hook = alc269_auto_init;
14698#ifdef CONFIG_SND_HDA_POWER_SAVE
14699 if (!spec->loopback.amplist)
14700 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014701 if (alc269_mic2_for_mute_led(codec))
14702 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014703#endif
14704
14705 return 0;
14706}
14707
14708/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014709 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14710 */
14711
14712/*
14713 * set the path ways for 2 channel output
14714 * need to set the codec line out and mic 1 pin widgets to inputs
14715 */
14716static struct hda_verb alc861_threestack_ch2_init[] = {
14717 /* set pin widget 1Ah (line in) for input */
14718 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014719 /* set pin widget 18h (mic1/2) for input, for mic also enable
14720 * the vref
14721 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014722 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14723
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014724 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14725#if 0
14726 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14727 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14728#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014729 { } /* end */
14730};
14731/*
14732 * 6ch mode
14733 * need to set the codec line out and mic 1 pin widgets to outputs
14734 */
14735static struct hda_verb alc861_threestack_ch6_init[] = {
14736 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14737 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14738 /* set pin widget 18h (mic1) for output (CLFE)*/
14739 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14740
14741 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014742 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014743
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014744 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14745#if 0
14746 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14747 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14748#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014749 { } /* end */
14750};
14751
14752static struct hda_channel_mode alc861_threestack_modes[2] = {
14753 { 2, alc861_threestack_ch2_init },
14754 { 6, alc861_threestack_ch6_init },
14755};
Takashi Iwai22309c32006-08-09 16:57:28 +020014756/* Set mic1 as input and unmute the mixer */
14757static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
14758 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14759 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14760 { } /* end */
14761};
14762/* Set mic1 as output and mute mixer */
14763static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
14764 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14765 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14766 { } /* end */
14767};
14768
14769static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
14770 { 2, alc861_uniwill_m31_ch2_init },
14771 { 4, alc861_uniwill_m31_ch4_init },
14772};
Kailang Yangdf694da2005-12-05 19:42:22 +010014773
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014774/* Set mic1 and line-in as input and unmute the mixer */
14775static struct hda_verb alc861_asus_ch2_init[] = {
14776 /* set pin widget 1Ah (line in) for input */
14777 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014778 /* set pin widget 18h (mic1/2) for input, for mic also enable
14779 * the vref
14780 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014781 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14782
14783 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14784#if 0
14785 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14786 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14787#endif
14788 { } /* end */
14789};
14790/* Set mic1 nad line-in as output and mute mixer */
14791static struct hda_verb alc861_asus_ch6_init[] = {
14792 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14793 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14794 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14795 /* set pin widget 18h (mic1) for output (CLFE)*/
14796 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14797 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14798 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14799 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14800
14801 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14802#if 0
14803 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14804 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14805#endif
14806 { } /* end */
14807};
14808
14809static struct hda_channel_mode alc861_asus_modes[2] = {
14810 { 2, alc861_asus_ch2_init },
14811 { 6, alc861_asus_ch6_init },
14812};
14813
Kailang Yangdf694da2005-12-05 19:42:22 +010014814/* patch-ALC861 */
14815
14816static struct snd_kcontrol_new alc861_base_mixer[] = {
14817 /* output mixer control */
14818 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14819 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14820 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14821 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14822 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14823
14824 /*Input mixer control */
14825 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14826 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14827 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14828 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14829 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14830 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14831 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14832 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14833 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14834 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014835
Kailang Yangdf694da2005-12-05 19:42:22 +010014836 { } /* end */
14837};
14838
14839static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14840 /* output mixer control */
14841 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14842 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14843 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14844 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14845 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14846
14847 /* Input mixer control */
14848 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14849 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14850 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14851 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14852 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14853 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14854 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14855 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14856 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14857 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014858
Kailang Yangdf694da2005-12-05 19:42:22 +010014859 {
14860 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14861 .name = "Channel Mode",
14862 .info = alc_ch_mode_info,
14863 .get = alc_ch_mode_get,
14864 .put = alc_ch_mode_put,
14865 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14866 },
14867 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014868};
14869
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014870static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014871 /* output mixer control */
14872 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14873 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14874 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014875
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014876 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014877};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014878
Takashi Iwai22309c32006-08-09 16:57:28 +020014879static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14880 /* output mixer control */
14881 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14882 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14883 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14884 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14885 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14886
14887 /* Input mixer control */
14888 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14889 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14890 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14891 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14892 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14893 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14894 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14895 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14896 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14897 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014898
Takashi Iwai22309c32006-08-09 16:57:28 +020014899 {
14900 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14901 .name = "Channel Mode",
14902 .info = alc_ch_mode_info,
14903 .get = alc_ch_mode_get,
14904 .put = alc_ch_mode_put,
14905 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14906 },
14907 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014908};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014909
14910static struct snd_kcontrol_new alc861_asus_mixer[] = {
14911 /* output mixer control */
14912 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14913 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14914 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14915 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14916 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14917
14918 /* Input mixer control */
14919 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14920 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14921 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14922 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14923 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14924 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14925 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14926 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14927 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14929
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014930 {
14931 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14932 .name = "Channel Mode",
14933 .info = alc_ch_mode_info,
14934 .get = alc_ch_mode_get,
14935 .put = alc_ch_mode_put,
14936 .private_value = ARRAY_SIZE(alc861_asus_modes),
14937 },
14938 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014939};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014940
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014941/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014942static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014943 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14944 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014945 { }
14946};
14947
Kailang Yangdf694da2005-12-05 19:42:22 +010014948/*
14949 * generic initialization of ADC, input mixers and output mixers
14950 */
14951static struct hda_verb alc861_base_init_verbs[] = {
14952 /*
14953 * Unmute ADC0 and set the default input to mic-in
14954 */
14955 /* port-A for surround (rear panel) */
14956 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14957 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14958 /* port-B for mic-in (rear panel) with vref */
14959 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14960 /* port-C for line-in (rear panel) */
14961 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14962 /* port-D for Front */
14963 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14964 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14965 /* port-E for HP out (front panel) */
14966 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14967 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014968 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014969 /* port-F for mic-in (front panel) with vref */
14970 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14971 /* port-G for CLFE (rear panel) */
14972 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14973 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14974 /* port-H for side (rear panel) */
14975 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14976 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14977 /* CD-in */
14978 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14979 /* route front mic to ADC1*/
14980 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14981 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014982
Kailang Yangdf694da2005-12-05 19:42:22 +010014983 /* Unmute DAC0~3 & spdif out*/
14984 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14985 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14986 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14987 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14988 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014989
Kailang Yangdf694da2005-12-05 19:42:22 +010014990 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14991 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14992 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14993 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14994 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014995
Kailang Yangdf694da2005-12-05 19:42:22 +010014996 /* Unmute Stereo Mixer 15 */
14997 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14998 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14999 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015000 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015001
15002 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15003 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15004 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15005 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15006 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15007 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15008 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15009 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015010 /* hp used DAC 3 (Front) */
15011 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015012 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15013
15014 { }
15015};
15016
15017static struct hda_verb alc861_threestack_init_verbs[] = {
15018 /*
15019 * Unmute ADC0 and set the default input to mic-in
15020 */
15021 /* port-A for surround (rear panel) */
15022 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15023 /* port-B for mic-in (rear panel) with vref */
15024 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15025 /* port-C for line-in (rear panel) */
15026 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15027 /* port-D for Front */
15028 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15029 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15030 /* port-E for HP out (front panel) */
15031 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15032 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015033 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015034 /* port-F for mic-in (front panel) with vref */
15035 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15036 /* port-G for CLFE (rear panel) */
15037 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15038 /* port-H for side (rear panel) */
15039 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15040 /* CD-in */
15041 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15042 /* route front mic to ADC1*/
15043 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15044 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15045 /* Unmute DAC0~3 & spdif out*/
15046 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15047 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15048 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15049 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15050 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015051
Kailang Yangdf694da2005-12-05 19:42:22 +010015052 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15053 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15054 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15055 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15056 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015057
Kailang Yangdf694da2005-12-05 19:42:22 +010015058 /* Unmute Stereo Mixer 15 */
15059 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15060 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15061 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015062 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015063
15064 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15065 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15066 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15067 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15068 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15069 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15070 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15071 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015072 /* hp used DAC 3 (Front) */
15073 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015074 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15075 { }
15076};
Takashi Iwai22309c32006-08-09 16:57:28 +020015077
15078static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15079 /*
15080 * Unmute ADC0 and set the default input to mic-in
15081 */
15082 /* port-A for surround (rear panel) */
15083 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15084 /* port-B for mic-in (rear panel) with vref */
15085 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15086 /* port-C for line-in (rear panel) */
15087 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15088 /* port-D for Front */
15089 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15090 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15091 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015092 /* this has to be set to VREF80 */
15093 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015094 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015095 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015096 /* port-F for mic-in (front panel) with vref */
15097 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15098 /* port-G for CLFE (rear panel) */
15099 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15100 /* port-H for side (rear panel) */
15101 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15102 /* CD-in */
15103 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15104 /* route front mic to ADC1*/
15105 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15106 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15107 /* Unmute DAC0~3 & spdif out*/
15108 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15109 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15110 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15111 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15112 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015113
Takashi Iwai22309c32006-08-09 16:57:28 +020015114 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15115 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15116 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15117 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15118 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015119
Takashi Iwai22309c32006-08-09 16:57:28 +020015120 /* Unmute Stereo Mixer 15 */
15121 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15122 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15123 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015124 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015125
15126 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15127 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15128 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15129 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15130 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15131 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15132 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15133 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015134 /* hp used DAC 3 (Front) */
15135 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015136 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15137 { }
15138};
15139
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015140static struct hda_verb alc861_asus_init_verbs[] = {
15141 /*
15142 * Unmute ADC0 and set the default input to mic-in
15143 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015144 /* port-A for surround (rear panel)
15145 * according to codec#0 this is the HP jack
15146 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015147 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15148 /* route front PCM to HP */
15149 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15150 /* port-B for mic-in (rear panel) with vref */
15151 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15152 /* port-C for line-in (rear panel) */
15153 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15154 /* port-D for Front */
15155 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15156 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15157 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015158 /* this has to be set to VREF80 */
15159 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015160 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015161 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015162 /* port-F for mic-in (front panel) with vref */
15163 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15164 /* port-G for CLFE (rear panel) */
15165 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15166 /* port-H for side (rear panel) */
15167 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15168 /* CD-in */
15169 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15170 /* route front mic to ADC1*/
15171 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15172 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15173 /* Unmute DAC0~3 & spdif out*/
15174 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15175 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15176 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15177 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15178 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15179 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15180 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15181 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15182 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15183 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015184
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015185 /* Unmute Stereo Mixer 15 */
15186 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15187 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15188 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015190
15191 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15192 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15193 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15194 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15195 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15196 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15197 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15198 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015199 /* hp used DAC 3 (Front) */
15200 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015201 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15202 { }
15203};
15204
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015205/* additional init verbs for ASUS laptops */
15206static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15207 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15208 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15209 { }
15210};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015211
Kailang Yangdf694da2005-12-05 19:42:22 +010015212/*
15213 * generic initialization of ADC, input mixers and output mixers
15214 */
15215static struct hda_verb alc861_auto_init_verbs[] = {
15216 /*
15217 * Unmute ADC0 and set the default input to mic-in
15218 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015219 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015220 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015221
Kailang Yangdf694da2005-12-05 19:42:22 +010015222 /* Unmute DAC0~3 & spdif out*/
15223 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15224 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15225 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15226 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15227 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015228
Kailang Yangdf694da2005-12-05 19:42:22 +010015229 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15230 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15231 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15232 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15233 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015234
Kailang Yangdf694da2005-12-05 19:42:22 +010015235 /* Unmute Stereo Mixer 15 */
15236 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15237 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15238 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15239 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15240
Takashi Iwai1c209302009-07-22 15:17:45 +020015241 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15242 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15243 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15244 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15245 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15246 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15247 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15248 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015249
15250 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15251 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015252 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15253 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015254 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15255 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015256 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15257 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015258
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015259 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015260
15261 { }
15262};
15263
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015264static struct hda_verb alc861_toshiba_init_verbs[] = {
15265 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015266
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015267 { }
15268};
15269
15270/* toggle speaker-output according to the hp-jack state */
15271static void alc861_toshiba_automute(struct hda_codec *codec)
15272{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015273 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015274
Takashi Iwai47fd8302007-08-10 17:11:07 +020015275 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15276 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15277 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15278 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015279}
15280
15281static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15282 unsigned int res)
15283{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015284 if ((res >> 26) == ALC880_HP_EVENT)
15285 alc861_toshiba_automute(codec);
15286}
15287
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015288/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015289#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15290#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15291#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15292#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15293
15294
15295#define ALC861_DIGOUT_NID 0x07
15296
15297static struct hda_channel_mode alc861_8ch_modes[1] = {
15298 { 8, NULL }
15299};
15300
15301static hda_nid_t alc861_dac_nids[4] = {
15302 /* front, surround, clfe, side */
15303 0x03, 0x06, 0x05, 0x04
15304};
15305
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015306static hda_nid_t alc660_dac_nids[3] = {
15307 /* front, clfe, surround */
15308 0x03, 0x05, 0x06
15309};
15310
Kailang Yangdf694da2005-12-05 19:42:22 +010015311static hda_nid_t alc861_adc_nids[1] = {
15312 /* ADC0-2 */
15313 0x08,
15314};
15315
15316static struct hda_input_mux alc861_capture_source = {
15317 .num_items = 5,
15318 .items = {
15319 { "Mic", 0x0 },
15320 { "Front Mic", 0x3 },
15321 { "Line", 0x1 },
15322 { "CD", 0x4 },
15323 { "Mixer", 0x5 },
15324 },
15325};
15326
Takashi Iwai1c209302009-07-22 15:17:45 +020015327static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15328{
15329 struct alc_spec *spec = codec->spec;
15330 hda_nid_t mix, srcs[5];
15331 int i, j, num;
15332
15333 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15334 return 0;
15335 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15336 if (num < 0)
15337 return 0;
15338 for (i = 0; i < num; i++) {
15339 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015340 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015341 if (type != AC_WID_AUD_OUT)
15342 continue;
15343 for (j = 0; j < spec->multiout.num_dacs; j++)
15344 if (spec->multiout.dac_nids[j] == srcs[i])
15345 break;
15346 if (j >= spec->multiout.num_dacs)
15347 return srcs[i];
15348 }
15349 return 0;
15350}
15351
Kailang Yangdf694da2005-12-05 19:42:22 +010015352/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015353static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015354 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015355{
Takashi Iwai1c209302009-07-22 15:17:45 +020015356 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015357 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015358 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015359
15360 spec->multiout.dac_nids = spec->private_dac_nids;
15361 for (i = 0; i < cfg->line_outs; i++) {
15362 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015363 dac = alc861_look_for_dac(codec, nid);
15364 if (!dac)
15365 continue;
15366 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015367 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015368 return 0;
15369}
15370
Takashi Iwai1c209302009-07-22 15:17:45 +020015371static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15372 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015373{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015374 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015375 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15376}
15377
15378/* add playback controls from the parsed DAC table */
15379static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15380 const struct auto_pin_cfg *cfg)
15381{
15382 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015383 static const char *chname[4] = {
15384 "Front", "Surround", NULL /*CLFE*/, "Side"
15385 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015386 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015387 int i, err;
15388
15389 if (cfg->line_outs == 1) {
15390 const char *pfx = NULL;
15391 if (!cfg->hp_outs)
15392 pfx = "Master";
15393 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15394 pfx = "Speaker";
15395 if (pfx) {
15396 nid = spec->multiout.dac_nids[0];
15397 return alc861_create_out_sw(codec, pfx, nid, 3);
15398 }
15399 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015400
15401 for (i = 0; i < cfg->line_outs; i++) {
15402 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015403 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015404 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015405 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015406 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015407 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015408 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015409 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015410 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015411 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015412 return err;
15413 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015414 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015415 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015416 return err;
15417 }
15418 }
15419 return 0;
15420}
15421
Takashi Iwai1c209302009-07-22 15:17:45 +020015422static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015423{
Takashi Iwai1c209302009-07-22 15:17:45 +020015424 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015425 int err;
15426 hda_nid_t nid;
15427
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015428 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015429 return 0;
15430
15431 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015432 nid = alc861_look_for_dac(codec, pin);
15433 if (nid) {
15434 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15435 if (err < 0)
15436 return err;
15437 spec->multiout.hp_nid = nid;
15438 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015439 }
15440 return 0;
15441}
15442
15443/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015444static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015445 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015446{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015447 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015448}
15449
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015450static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15451 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015452 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015453{
Takashi Iwai1c209302009-07-22 15:17:45 +020015454 hda_nid_t mix, srcs[5];
15455 int i, num;
15456
Jacek Luczak564c5be2008-05-03 18:41:23 +020015457 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15458 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015459 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015460 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015461 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15462 return;
15463 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15464 if (num < 0)
15465 return;
15466 for (i = 0; i < num; i++) {
15467 unsigned int mute;
15468 if (srcs[i] == dac || srcs[i] == 0x15)
15469 mute = AMP_IN_UNMUTE(i);
15470 else
15471 mute = AMP_IN_MUTE(i);
15472 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15473 mute);
15474 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015475}
15476
15477static void alc861_auto_init_multi_out(struct hda_codec *codec)
15478{
15479 struct alc_spec *spec = codec->spec;
15480 int i;
15481
15482 for (i = 0; i < spec->autocfg.line_outs; i++) {
15483 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015484 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015485 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015486 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015487 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015488 }
15489}
15490
15491static void alc861_auto_init_hp_out(struct hda_codec *codec)
15492{
15493 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015494
Takashi Iwai15870f02009-10-05 08:25:13 +020015495 if (spec->autocfg.hp_outs)
15496 alc861_auto_set_output_and_unmute(codec,
15497 spec->autocfg.hp_pins[0],
15498 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015499 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015500 if (spec->autocfg.speaker_outs)
15501 alc861_auto_set_output_and_unmute(codec,
15502 spec->autocfg.speaker_pins[0],
15503 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015504 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015505}
15506
15507static void alc861_auto_init_analog_input(struct hda_codec *codec)
15508{
15509 struct alc_spec *spec = codec->spec;
15510 int i;
15511
15512 for (i = 0; i < AUTO_PIN_LAST; i++) {
15513 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010015514 if (nid >= 0x0c && nid <= 0x11)
15515 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010015516 }
15517}
15518
15519/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015520/* return 1 if successful, 0 if the proper config is not found,
15521 * or a negative error code
15522 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015523static int alc861_parse_auto_config(struct hda_codec *codec)
15524{
15525 struct alc_spec *spec = codec->spec;
15526 int err;
15527 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15528
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015529 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15530 alc861_ignore);
15531 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015532 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015533 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015534 return 0; /* can't find valid BIOS pin config */
15535
Takashi Iwai1c209302009-07-22 15:17:45 +020015536 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015537 if (err < 0)
15538 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015539 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015540 if (err < 0)
15541 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015542 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015543 if (err < 0)
15544 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015545 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015546 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015547 return err;
15548
15549 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15550
Takashi Iwai757899a2010-07-30 10:48:14 +020015551 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015552
Takashi Iwai603c4012008-07-30 15:01:44 +020015553 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015554 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015555
Takashi Iwaid88897e2008-10-31 15:01:37 +010015556 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015557
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015558 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015559 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015560
15561 spec->adc_nids = alc861_adc_nids;
15562 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015563 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015564
Kailang Yang6227cdc2010-02-25 08:36:52 +010015565 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015566
Kailang Yangdf694da2005-12-05 19:42:22 +010015567 return 1;
15568}
15569
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015570/* additional initialization for auto-configuration model */
15571static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015572{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015573 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015574 alc861_auto_init_multi_out(codec);
15575 alc861_auto_init_hp_out(codec);
15576 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015577 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015578 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015579 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015580}
15581
Takashi Iwaicb53c622007-08-10 17:21:45 +020015582#ifdef CONFIG_SND_HDA_POWER_SAVE
15583static struct hda_amp_list alc861_loopbacks[] = {
15584 { 0x15, HDA_INPUT, 0 },
15585 { 0x15, HDA_INPUT, 1 },
15586 { 0x15, HDA_INPUT, 2 },
15587 { 0x15, HDA_INPUT, 3 },
15588 { } /* end */
15589};
15590#endif
15591
Kailang Yangdf694da2005-12-05 19:42:22 +010015592
15593/*
15594 * configuration and preset
15595 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015596static const char *alc861_models[ALC861_MODEL_LAST] = {
15597 [ALC861_3ST] = "3stack",
15598 [ALC660_3ST] = "3stack-660",
15599 [ALC861_3ST_DIG] = "3stack-dig",
15600 [ALC861_6ST_DIG] = "6stack-dig",
15601 [ALC861_UNIWILL_M31] = "uniwill-m31",
15602 [ALC861_TOSHIBA] = "toshiba",
15603 [ALC861_ASUS] = "asus",
15604 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15605 [ALC861_AUTO] = "auto",
15606};
15607
15608static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015609 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015610 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15611 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15612 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015613 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015614 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015615 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015616 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15617 * Any other models that need this preset?
15618 */
15619 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015620 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15621 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015622 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15623 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15624 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15625 /* FIXME: the below seems conflict */
15626 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15627 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15628 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015629 {}
15630};
15631
15632static struct alc_config_preset alc861_presets[] = {
15633 [ALC861_3ST] = {
15634 .mixers = { alc861_3ST_mixer },
15635 .init_verbs = { alc861_threestack_init_verbs },
15636 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15637 .dac_nids = alc861_dac_nids,
15638 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15639 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015640 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015641 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15642 .adc_nids = alc861_adc_nids,
15643 .input_mux = &alc861_capture_source,
15644 },
15645 [ALC861_3ST_DIG] = {
15646 .mixers = { alc861_base_mixer },
15647 .init_verbs = { alc861_threestack_init_verbs },
15648 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15649 .dac_nids = alc861_dac_nids,
15650 .dig_out_nid = ALC861_DIGOUT_NID,
15651 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15652 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015653 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015654 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15655 .adc_nids = alc861_adc_nids,
15656 .input_mux = &alc861_capture_source,
15657 },
15658 [ALC861_6ST_DIG] = {
15659 .mixers = { alc861_base_mixer },
15660 .init_verbs = { alc861_base_init_verbs },
15661 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15662 .dac_nids = alc861_dac_nids,
15663 .dig_out_nid = ALC861_DIGOUT_NID,
15664 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15665 .channel_mode = alc861_8ch_modes,
15666 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15667 .adc_nids = alc861_adc_nids,
15668 .input_mux = &alc861_capture_source,
15669 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015670 [ALC660_3ST] = {
15671 .mixers = { alc861_3ST_mixer },
15672 .init_verbs = { alc861_threestack_init_verbs },
15673 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15674 .dac_nids = alc660_dac_nids,
15675 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15676 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015677 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015678 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15679 .adc_nids = alc861_adc_nids,
15680 .input_mux = &alc861_capture_source,
15681 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015682 [ALC861_UNIWILL_M31] = {
15683 .mixers = { alc861_uniwill_m31_mixer },
15684 .init_verbs = { alc861_uniwill_m31_init_verbs },
15685 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15686 .dac_nids = alc861_dac_nids,
15687 .dig_out_nid = ALC861_DIGOUT_NID,
15688 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15689 .channel_mode = alc861_uniwill_m31_modes,
15690 .need_dac_fix = 1,
15691 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15692 .adc_nids = alc861_adc_nids,
15693 .input_mux = &alc861_capture_source,
15694 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015695 [ALC861_TOSHIBA] = {
15696 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015697 .init_verbs = { alc861_base_init_verbs,
15698 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015699 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15700 .dac_nids = alc861_dac_nids,
15701 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15702 .channel_mode = alc883_3ST_2ch_modes,
15703 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15704 .adc_nids = alc861_adc_nids,
15705 .input_mux = &alc861_capture_source,
15706 .unsol_event = alc861_toshiba_unsol_event,
15707 .init_hook = alc861_toshiba_automute,
15708 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015709 [ALC861_ASUS] = {
15710 .mixers = { alc861_asus_mixer },
15711 .init_verbs = { alc861_asus_init_verbs },
15712 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15713 .dac_nids = alc861_dac_nids,
15714 .dig_out_nid = ALC861_DIGOUT_NID,
15715 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15716 .channel_mode = alc861_asus_modes,
15717 .need_dac_fix = 1,
15718 .hp_nid = 0x06,
15719 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15720 .adc_nids = alc861_adc_nids,
15721 .input_mux = &alc861_capture_source,
15722 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015723 [ALC861_ASUS_LAPTOP] = {
15724 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15725 .init_verbs = { alc861_asus_init_verbs,
15726 alc861_asus_laptop_init_verbs },
15727 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15728 .dac_nids = alc861_dac_nids,
15729 .dig_out_nid = ALC861_DIGOUT_NID,
15730 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15731 .channel_mode = alc883_3ST_2ch_modes,
15732 .need_dac_fix = 1,
15733 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15734 .adc_nids = alc861_adc_nids,
15735 .input_mux = &alc861_capture_source,
15736 },
15737};
Kailang Yangdf694da2005-12-05 19:42:22 +010015738
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015739/* Pin config fixes */
15740enum {
15741 PINFIX_FSC_AMILO_PI1505,
15742};
15743
15744static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
15745 { 0x0b, 0x0221101f }, /* HP */
15746 { 0x0f, 0x90170310 }, /* speaker */
15747 { }
15748};
15749
15750static const struct alc_fixup alc861_fixups[] = {
15751 [PINFIX_FSC_AMILO_PI1505] = {
15752 .pins = alc861_fsc_amilo_pi1505_pinfix
15753 },
15754};
15755
15756static struct snd_pci_quirk alc861_fixup_tbl[] = {
15757 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15758 {}
15759};
Kailang Yangdf694da2005-12-05 19:42:22 +010015760
15761static int patch_alc861(struct hda_codec *codec)
15762{
15763 struct alc_spec *spec;
15764 int board_config;
15765 int err;
15766
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015767 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015768 if (spec == NULL)
15769 return -ENOMEM;
15770
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015771 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015772
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015773 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15774 alc861_models,
15775 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015776
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015777 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015778 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15779 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015780 board_config = ALC861_AUTO;
15781 }
15782
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015783 if (board_config == ALC861_AUTO)
15784 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015785
Kailang Yangdf694da2005-12-05 19:42:22 +010015786 if (board_config == ALC861_AUTO) {
15787 /* automatic parse from the BIOS config */
15788 err = alc861_parse_auto_config(codec);
15789 if (err < 0) {
15790 alc_free(codec);
15791 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015792 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015793 printk(KERN_INFO
15794 "hda_codec: Cannot set up configuration "
15795 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015796 board_config = ALC861_3ST_DIG;
15797 }
15798 }
15799
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015800 err = snd_hda_attach_beep_device(codec, 0x23);
15801 if (err < 0) {
15802 alc_free(codec);
15803 return err;
15804 }
15805
Kailang Yangdf694da2005-12-05 19:42:22 +010015806 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015807 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015808
Kailang Yangdf694da2005-12-05 19:42:22 +010015809 spec->stream_analog_playback = &alc861_pcm_analog_playback;
15810 spec->stream_analog_capture = &alc861_pcm_analog_capture;
15811
Kailang Yangdf694da2005-12-05 19:42:22 +010015812 spec->stream_digital_playback = &alc861_pcm_digital_playback;
15813 spec->stream_digital_capture = &alc861_pcm_digital_capture;
15814
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015815 if (!spec->cap_mixer)
15816 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015817 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15818
Takashi Iwai2134ea42008-01-10 16:53:55 +010015819 spec->vmaster_nid = 0x03;
15820
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015821 if (board_config == ALC861_AUTO)
15822 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
15823
Kailang Yangdf694da2005-12-05 19:42:22 +010015824 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015825 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015826 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015827#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015828 spec->power_hook = alc_power_eapd;
15829#endif
15830 }
15831#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015832 if (!spec->loopback.amplist)
15833 spec->loopback.amplist = alc861_loopbacks;
15834#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015835
Kailang Yangdf694da2005-12-05 19:42:22 +010015836 return 0;
15837}
15838
15839/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015840 * ALC861-VD support
15841 *
15842 * Based on ALC882
15843 *
15844 * In addition, an independent DAC
15845 */
15846#define ALC861VD_DIGOUT_NID 0x06
15847
15848static hda_nid_t alc861vd_dac_nids[4] = {
15849 /* front, surr, clfe, side surr */
15850 0x02, 0x03, 0x04, 0x05
15851};
15852
15853/* dac_nids for ALC660vd are in a different order - according to
15854 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015855 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015856 * of ALC660vd codecs, but for now there is only 3stack mixer
15857 * - and it is the same as in 861vd.
15858 * adc_nids in ALC660vd are (is) the same as in 861vd
15859 */
15860static hda_nid_t alc660vd_dac_nids[3] = {
15861 /* front, rear, clfe, rear_surr */
15862 0x02, 0x04, 0x03
15863};
15864
15865static hda_nid_t alc861vd_adc_nids[1] = {
15866 /* ADC0 */
15867 0x09,
15868};
15869
Takashi Iwaie1406342008-02-11 18:32:32 +010015870static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15871
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015872/* input MUX */
15873/* FIXME: should be a matrix-type input source selection */
15874static struct hda_input_mux alc861vd_capture_source = {
15875 .num_items = 4,
15876 .items = {
15877 { "Mic", 0x0 },
15878 { "Front Mic", 0x1 },
15879 { "Line", 0x2 },
15880 { "CD", 0x4 },
15881 },
15882};
15883
Kailang Yang272a5272007-05-14 11:00:38 +020015884static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015885 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015886 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015887 { "Ext Mic", 0x0 },
15888 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015889 },
15890};
15891
Kailang Yangd1a991a2007-08-15 16:21:59 +020015892static struct hda_input_mux alc861vd_hp_capture_source = {
15893 .num_items = 2,
15894 .items = {
15895 { "Front Mic", 0x0 },
15896 { "ATAPI Mic", 0x1 },
15897 },
15898};
15899
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015900/*
15901 * 2ch mode
15902 */
15903static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15904 { 2, NULL }
15905};
15906
15907/*
15908 * 6ch mode
15909 */
15910static struct hda_verb alc861vd_6stack_ch6_init[] = {
15911 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15912 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15913 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15914 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15915 { } /* end */
15916};
15917
15918/*
15919 * 8ch mode
15920 */
15921static struct hda_verb alc861vd_6stack_ch8_init[] = {
15922 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15923 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15924 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15925 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15926 { } /* end */
15927};
15928
15929static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15930 { 6, alc861vd_6stack_ch6_init },
15931 { 8, alc861vd_6stack_ch8_init },
15932};
15933
15934static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15935 {
15936 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15937 .name = "Channel Mode",
15938 .info = alc_ch_mode_info,
15939 .get = alc_ch_mode_get,
15940 .put = alc_ch_mode_put,
15941 },
15942 { } /* end */
15943};
15944
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015945/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15946 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15947 */
15948static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15949 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15950 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15951
15952 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15953 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15954
15955 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15956 HDA_OUTPUT),
15957 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15958 HDA_OUTPUT),
15959 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15960 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15961
15962 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15963 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15964
15965 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15966
15967 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15968 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15969 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15970
15971 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15972 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15973 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15974
15975 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15976 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15977
15978 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15979 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15980
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015981 { } /* end */
15982};
15983
15984static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15985 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15986 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15987
15988 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15989
15990 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15991 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15992 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15993
15994 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15995 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15996 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15997
15998 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15999 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16000
16001 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16002 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16003
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016004 { } /* end */
16005};
16006
Kailang Yangbdd148a2007-05-08 15:19:08 +020016007static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16008 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16009 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16010 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16011
16012 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16013
16014 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16015 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16016 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16017
16018 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16019 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16020 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16021
16022 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16023 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16024
16025 { } /* end */
16026};
16027
Tobin Davisb419f342008-03-07 11:57:51 +010016028/* Pin assignment: Speaker=0x14, HP = 0x15,
16029 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016030 */
16031static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016032 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16033 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016034 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16035 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010016036 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16037 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16038 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16039 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16040 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16041 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016042 { } /* end */
16043};
16044
Kailang Yangd1a991a2007-08-15 16:21:59 +020016045/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16046 * Front Mic=0x18, ATAPI Mic = 0x19,
16047 */
16048static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16049 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16050 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16051 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16052 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16053 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16054 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16055 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16056 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016057
Kailang Yangd1a991a2007-08-15 16:21:59 +020016058 { } /* end */
16059};
16060
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016061/*
16062 * generic initialization of ADC, input mixers and output mixers
16063 */
16064static struct hda_verb alc861vd_volume_init_verbs[] = {
16065 /*
16066 * Unmute ADC0 and set the default input to mic-in
16067 */
16068 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16069 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16070
16071 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16072 * the analog-loopback mixer widget
16073 */
16074 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016075 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16076 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16077 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16078 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16079 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016080
16081 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016082 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016086
16087 /*
16088 * Set up output mixers (0x02 - 0x05)
16089 */
16090 /* set vol=0 to output mixers */
16091 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16092 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16093 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16094 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16095
16096 /* set up input amps for analog loopback */
16097 /* Amp Indices: DAC = 0, mixer = 1 */
16098 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16099 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16100 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16101 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16102 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16103 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16104 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16105 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16106
16107 { }
16108};
16109
16110/*
16111 * 3-stack pin configuration:
16112 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16113 */
16114static struct hda_verb alc861vd_3stack_init_verbs[] = {
16115 /*
16116 * Set pin mode and muting
16117 */
16118 /* set front pin widgets 0x14 for output */
16119 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16120 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16121 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16122
16123 /* Mic (rear) pin: input vref at 80% */
16124 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16125 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16126 /* Front Mic pin: input vref at 80% */
16127 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16128 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16129 /* Line In pin: input */
16130 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16131 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16132 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16133 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16134 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16135 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16136 /* CD pin widget for input */
16137 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16138
16139 { }
16140};
16141
16142/*
16143 * 6-stack pin configuration:
16144 */
16145static struct hda_verb alc861vd_6stack_init_verbs[] = {
16146 /*
16147 * Set pin mode and muting
16148 */
16149 /* set front pin widgets 0x14 for output */
16150 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16151 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16152 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16153
16154 /* Rear Pin: output 1 (0x0d) */
16155 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16156 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16157 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16158 /* CLFE Pin: output 2 (0x0e) */
16159 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16160 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16161 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16162 /* Side Pin: output 3 (0x0f) */
16163 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16164 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16165 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16166
16167 /* Mic (rear) pin: input vref at 80% */
16168 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16169 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16170 /* Front Mic pin: input vref at 80% */
16171 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16172 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16173 /* Line In pin: input */
16174 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16175 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16176 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16177 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16178 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16179 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16180 /* CD pin widget for input */
16181 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16182
16183 { }
16184};
16185
Kailang Yangbdd148a2007-05-08 15:19:08 +020016186static struct hda_verb alc861vd_eapd_verbs[] = {
16187 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16188 { }
16189};
16190
Kailang Yangf9423e72008-05-27 12:32:25 +020016191static struct hda_verb alc660vd_eapd_verbs[] = {
16192 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16193 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16194 { }
16195};
16196
Kailang Yangbdd148a2007-05-08 15:19:08 +020016197static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16198 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16199 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16200 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16201 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016202 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016203 {}
16204};
16205
Kailang Yangbdd148a2007-05-08 15:19:08 +020016206static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16207{
16208 unsigned int present;
16209 unsigned char bits;
16210
Wu Fengguang864f92b2009-11-18 12:38:02 +080016211 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016212 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016213
Takashi Iwai47fd8302007-08-10 17:11:07 +020016214 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16215 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016216}
16217
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016218static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016219{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016220 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016221 spec->autocfg.hp_pins[0] = 0x1b;
16222 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016223}
16224
16225static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16226{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016227 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016228 alc861vd_lenovo_mic_automute(codec);
16229}
16230
16231static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16232 unsigned int res)
16233{
16234 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016235 case ALC880_MIC_EVENT:
16236 alc861vd_lenovo_mic_automute(codec);
16237 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016238 default:
16239 alc_automute_amp_unsol_event(codec, res);
16240 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016241 }
16242}
16243
Kailang Yang272a5272007-05-14 11:00:38 +020016244static struct hda_verb alc861vd_dallas_verbs[] = {
16245 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16246 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16247 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16248 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16249
16250 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16251 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16252 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16253 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16254 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16255 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16256 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16257 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016258
Kailang Yang272a5272007-05-14 11:00:38 +020016259 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16260 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16261 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16262 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16263 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16264 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16265 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16266 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16267
16268 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16269 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16270 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16271 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16272 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16273 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16274 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16275 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16276
16277 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16278 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16279 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16280 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16281
16282 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016283 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016284 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16285
16286 { } /* end */
16287};
16288
16289/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016290static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016291{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016292 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016293
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016294 spec->autocfg.hp_pins[0] = 0x15;
16295 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016296}
16297
Takashi Iwaicb53c622007-08-10 17:21:45 +020016298#ifdef CONFIG_SND_HDA_POWER_SAVE
16299#define alc861vd_loopbacks alc880_loopbacks
16300#endif
16301
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016302/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016303#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16304#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16305#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16306#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16307
16308/*
16309 * configuration and preset
16310 */
16311static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16312 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016313 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016314 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016315 [ALC861VD_3ST] = "3stack",
16316 [ALC861VD_3ST_DIG] = "3stack-digout",
16317 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016318 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016319 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016320 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016321 [ALC861VD_AUTO] = "auto",
16322};
16323
16324static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016325 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16326 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016327 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016328 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016329 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016330 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016331 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016332 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016333 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016334 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016335 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016336 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016337 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016338 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016339 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016340 {}
16341};
16342
16343static struct alc_config_preset alc861vd_presets[] = {
16344 [ALC660VD_3ST] = {
16345 .mixers = { alc861vd_3st_mixer },
16346 .init_verbs = { alc861vd_volume_init_verbs,
16347 alc861vd_3stack_init_verbs },
16348 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16349 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016350 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16351 .channel_mode = alc861vd_3stack_2ch_modes,
16352 .input_mux = &alc861vd_capture_source,
16353 },
Mike Crash6963f842007-06-25 12:12:51 +020016354 [ALC660VD_3ST_DIG] = {
16355 .mixers = { alc861vd_3st_mixer },
16356 .init_verbs = { alc861vd_volume_init_verbs,
16357 alc861vd_3stack_init_verbs },
16358 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16359 .dac_nids = alc660vd_dac_nids,
16360 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016361 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16362 .channel_mode = alc861vd_3stack_2ch_modes,
16363 .input_mux = &alc861vd_capture_source,
16364 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016365 [ALC861VD_3ST] = {
16366 .mixers = { alc861vd_3st_mixer },
16367 .init_verbs = { alc861vd_volume_init_verbs,
16368 alc861vd_3stack_init_verbs },
16369 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16370 .dac_nids = alc861vd_dac_nids,
16371 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16372 .channel_mode = alc861vd_3stack_2ch_modes,
16373 .input_mux = &alc861vd_capture_source,
16374 },
16375 [ALC861VD_3ST_DIG] = {
16376 .mixers = { alc861vd_3st_mixer },
16377 .init_verbs = { alc861vd_volume_init_verbs,
16378 alc861vd_3stack_init_verbs },
16379 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16380 .dac_nids = alc861vd_dac_nids,
16381 .dig_out_nid = ALC861VD_DIGOUT_NID,
16382 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16383 .channel_mode = alc861vd_3stack_2ch_modes,
16384 .input_mux = &alc861vd_capture_source,
16385 },
16386 [ALC861VD_6ST_DIG] = {
16387 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16388 .init_verbs = { alc861vd_volume_init_verbs,
16389 alc861vd_6stack_init_verbs },
16390 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16391 .dac_nids = alc861vd_dac_nids,
16392 .dig_out_nid = ALC861VD_DIGOUT_NID,
16393 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16394 .channel_mode = alc861vd_6stack_modes,
16395 .input_mux = &alc861vd_capture_source,
16396 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016397 [ALC861VD_LENOVO] = {
16398 .mixers = { alc861vd_lenovo_mixer },
16399 .init_verbs = { alc861vd_volume_init_verbs,
16400 alc861vd_3stack_init_verbs,
16401 alc861vd_eapd_verbs,
16402 alc861vd_lenovo_unsol_verbs },
16403 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16404 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016405 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16406 .channel_mode = alc861vd_3stack_2ch_modes,
16407 .input_mux = &alc861vd_capture_source,
16408 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016409 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016410 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016411 },
Kailang Yang272a5272007-05-14 11:00:38 +020016412 [ALC861VD_DALLAS] = {
16413 .mixers = { alc861vd_dallas_mixer },
16414 .init_verbs = { alc861vd_dallas_verbs },
16415 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16416 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016417 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16418 .channel_mode = alc861vd_3stack_2ch_modes,
16419 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016420 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016421 .setup = alc861vd_dallas_setup,
16422 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016423 },
16424 [ALC861VD_HP] = {
16425 .mixers = { alc861vd_hp_mixer },
16426 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16427 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16428 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016429 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016430 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16431 .channel_mode = alc861vd_3stack_2ch_modes,
16432 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016433 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016434 .setup = alc861vd_dallas_setup,
16435 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016436 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016437 [ALC660VD_ASUS_V1S] = {
16438 .mixers = { alc861vd_lenovo_mixer },
16439 .init_verbs = { alc861vd_volume_init_verbs,
16440 alc861vd_3stack_init_verbs,
16441 alc861vd_eapd_verbs,
16442 alc861vd_lenovo_unsol_verbs },
16443 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16444 .dac_nids = alc660vd_dac_nids,
16445 .dig_out_nid = ALC861VD_DIGOUT_NID,
16446 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16447 .channel_mode = alc861vd_3stack_2ch_modes,
16448 .input_mux = &alc861vd_capture_source,
16449 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016450 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016451 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016452 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016453};
16454
16455/*
16456 * BIOS auto configuration
16457 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016458static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16459 const struct auto_pin_cfg *cfg)
16460{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016461 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016462}
16463
16464
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016465static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16466 hda_nid_t nid, int pin_type, int dac_idx)
16467{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016468 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016469}
16470
16471static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16472{
16473 struct alc_spec *spec = codec->spec;
16474 int i;
16475
16476 for (i = 0; i <= HDA_SIDE; i++) {
16477 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016478 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016479 if (nid)
16480 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016481 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016482 }
16483}
16484
16485
16486static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16487{
16488 struct alc_spec *spec = codec->spec;
16489 hda_nid_t pin;
16490
16491 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016492 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016493 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016494 pin = spec->autocfg.speaker_pins[0];
16495 if (pin)
16496 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016497}
16498
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016499#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16500
16501static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16502{
16503 struct alc_spec *spec = codec->spec;
16504 int i;
16505
16506 for (i = 0; i < AUTO_PIN_LAST; i++) {
16507 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020016508 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016509 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016510 if (nid != ALC861VD_PIN_CD_NID &&
16511 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016512 snd_hda_codec_write(codec, nid, 0,
16513 AC_VERB_SET_AMP_GAIN_MUTE,
16514 AMP_OUT_MUTE);
16515 }
16516 }
16517}
16518
Takashi Iwaif511b012008-08-15 16:46:42 +020016519#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16520
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016521#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16522#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16523
16524/* add playback controls from the parsed DAC table */
16525/* Based on ALC880 version. But ALC861VD has separate,
16526 * different NIDs for mute/unmute switch and volume control */
16527static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16528 const struct auto_pin_cfg *cfg)
16529{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016530 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16531 hda_nid_t nid_v, nid_s;
16532 int i, err;
16533
16534 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016535 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016536 continue;
16537 nid_v = alc861vd_idx_to_mixer_vol(
16538 alc880_dac_to_idx(
16539 spec->multiout.dac_nids[i]));
16540 nid_s = alc861vd_idx_to_mixer_switch(
16541 alc880_dac_to_idx(
16542 spec->multiout.dac_nids[i]));
16543
16544 if (i == 2) {
16545 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016546 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16547 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016548 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16549 HDA_OUTPUT));
16550 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016551 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016552 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16553 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016554 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16555 HDA_OUTPUT));
16556 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016557 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016558 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16559 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016560 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16561 HDA_INPUT));
16562 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016563 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016564 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16565 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016566 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16567 HDA_INPUT));
16568 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016569 return err;
16570 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016571 const char *pfx;
16572 if (cfg->line_outs == 1 &&
16573 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16574 if (!cfg->hp_pins)
16575 pfx = "Speaker";
16576 else
16577 pfx = "PCM";
16578 } else
16579 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016580 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016581 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16582 HDA_OUTPUT));
16583 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016584 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016585 if (cfg->line_outs == 1 &&
16586 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16587 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016588 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016589 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016590 HDA_INPUT));
16591 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016592 return err;
16593 }
16594 }
16595 return 0;
16596}
16597
16598/* add playback controls for speaker and HP outputs */
16599/* Based on ALC880 version. But ALC861VD has separate,
16600 * different NIDs for mute/unmute switch and volume control */
16601static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16602 hda_nid_t pin, const char *pfx)
16603{
16604 hda_nid_t nid_v, nid_s;
16605 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016606
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016607 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016608 return 0;
16609
16610 if (alc880_is_fixed_pin(pin)) {
16611 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16612 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016613 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016614 spec->multiout.hp_nid = nid_v;
16615 else
16616 spec->multiout.extra_out_nid[0] = nid_v;
16617 /* control HP volume/switch on the output mixer amp */
16618 nid_v = alc861vd_idx_to_mixer_vol(
16619 alc880_fixed_pin_idx(pin));
16620 nid_s = alc861vd_idx_to_mixer_switch(
16621 alc880_fixed_pin_idx(pin));
16622
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016623 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016624 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16625 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016626 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016627 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016628 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16629 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016630 return err;
16631 } else if (alc880_is_multi_pin(pin)) {
16632 /* set manual connection */
16633 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016634 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016635 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16636 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016637 return err;
16638 }
16639 return 0;
16640}
16641
16642/* parse the BIOS configuration and set up the alc_spec
16643 * return 1 if successful, 0 if the proper config is not found,
16644 * or a negative error code
16645 * Based on ALC880 version - had to change it to override
16646 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16647static int alc861vd_parse_auto_config(struct hda_codec *codec)
16648{
16649 struct alc_spec *spec = codec->spec;
16650 int err;
16651 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
16652
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016653 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16654 alc861vd_ignore);
16655 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016656 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016657 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016658 return 0; /* can't find valid BIOS pin config */
16659
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016660 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16661 if (err < 0)
16662 return err;
16663 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16664 if (err < 0)
16665 return err;
16666 err = alc861vd_auto_create_extra_out(spec,
16667 spec->autocfg.speaker_pins[0],
16668 "Speaker");
16669 if (err < 0)
16670 return err;
16671 err = alc861vd_auto_create_extra_out(spec,
16672 spec->autocfg.hp_pins[0],
16673 "Headphone");
16674 if (err < 0)
16675 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016676 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016677 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016678 return err;
16679
16680 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16681
Takashi Iwai757899a2010-07-30 10:48:14 +020016682 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016683
Takashi Iwai603c4012008-07-30 15:01:44 +020016684 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016685 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016686
Takashi Iwaid88897e2008-10-31 15:01:37 +010016687 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016688
16689 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016690 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016691
Takashi Iwai776e1842007-08-29 15:07:11 +020016692 err = alc_auto_add_mic_boost(codec);
16693 if (err < 0)
16694 return err;
16695
Kailang Yang6227cdc2010-02-25 08:36:52 +010016696 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016697
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016698 return 1;
16699}
16700
16701/* additional initialization for auto-configuration model */
16702static void alc861vd_auto_init(struct hda_codec *codec)
16703{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016704 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016705 alc861vd_auto_init_multi_out(codec);
16706 alc861vd_auto_init_hp_out(codec);
16707 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016708 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016709 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016710 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016711 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016712}
16713
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016714enum {
16715 ALC660VD_FIX_ASUS_GPIO1
16716};
16717
16718/* reset GPIO1 */
16719static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
16720 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16721 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16722 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16723 { }
16724};
16725
16726static const struct alc_fixup alc861vd_fixups[] = {
16727 [ALC660VD_FIX_ASUS_GPIO1] = {
16728 .verbs = alc660vd_fix_asus_gpio1_verbs,
16729 },
16730};
16731
16732static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
16733 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16734 {}
16735};
16736
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016737static int patch_alc861vd(struct hda_codec *codec)
16738{
16739 struct alc_spec *spec;
16740 int err, board_config;
16741
16742 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16743 if (spec == NULL)
16744 return -ENOMEM;
16745
16746 codec->spec = spec;
16747
16748 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16749 alc861vd_models,
16750 alc861vd_cfg_tbl);
16751
16752 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016753 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16754 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016755 board_config = ALC861VD_AUTO;
16756 }
16757
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016758 if (board_config == ALC861VD_AUTO)
16759 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016760
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016761 if (board_config == ALC861VD_AUTO) {
16762 /* automatic parse from the BIOS config */
16763 err = alc861vd_parse_auto_config(codec);
16764 if (err < 0) {
16765 alc_free(codec);
16766 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016767 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016768 printk(KERN_INFO
16769 "hda_codec: Cannot set up configuration "
16770 "from BIOS. Using base mode...\n");
16771 board_config = ALC861VD_3ST;
16772 }
16773 }
16774
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016775 err = snd_hda_attach_beep_device(codec, 0x23);
16776 if (err < 0) {
16777 alc_free(codec);
16778 return err;
16779 }
16780
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016781 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016782 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016783
Kailang Yang2f893282008-05-27 12:14:47 +020016784 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016785 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016786 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016787 }
16788
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016789 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16790 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16791
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016792 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16793 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16794
Takashi Iwaidd704692009-08-11 08:45:11 +020016795 if (!spec->adc_nids) {
16796 spec->adc_nids = alc861vd_adc_nids;
16797 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16798 }
16799 if (!spec->capsrc_nids)
16800 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016801
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016802 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016803 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016804
Takashi Iwai2134ea42008-01-10 16:53:55 +010016805 spec->vmaster_nid = 0x02;
16806
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016807 if (board_config == ALC861VD_AUTO)
16808 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
16809
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016810 codec->patch_ops = alc_patch_ops;
16811
16812 if (board_config == ALC861VD_AUTO)
16813 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016814#ifdef CONFIG_SND_HDA_POWER_SAVE
16815 if (!spec->loopback.amplist)
16816 spec->loopback.amplist = alc861vd_loopbacks;
16817#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016818
16819 return 0;
16820}
16821
16822/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016823 * ALC662 support
16824 *
16825 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16826 * configuration. Each pin widget can choose any input DACs and a mixer.
16827 * Each ADC is connected from a mixer of all inputs. This makes possible
16828 * 6-channel independent captures.
16829 *
16830 * In addition, an independent DAC for the multi-playback (not used in this
16831 * driver yet).
16832 */
16833#define ALC662_DIGOUT_NID 0x06
16834#define ALC662_DIGIN_NID 0x0a
16835
16836static hda_nid_t alc662_dac_nids[4] = {
16837 /* front, rear, clfe, rear_surr */
16838 0x02, 0x03, 0x04
16839};
16840
Kailang Yang622e84c2009-04-21 07:39:04 +020016841static hda_nid_t alc272_dac_nids[2] = {
16842 0x02, 0x03
16843};
16844
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016845static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016846 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016847 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016848};
Takashi Iwaie1406342008-02-11 18:32:32 +010016849
Kailang Yang622e84c2009-04-21 07:39:04 +020016850static hda_nid_t alc272_adc_nids[1] = {
16851 /* ADC1-2 */
16852 0x08,
16853};
16854
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016855static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016856static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16857
Takashi Iwaie1406342008-02-11 18:32:32 +010016858
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016859/* input MUX */
16860/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016861static struct hda_input_mux alc662_capture_source = {
16862 .num_items = 4,
16863 .items = {
16864 { "Mic", 0x0 },
16865 { "Front Mic", 0x1 },
16866 { "Line", 0x2 },
16867 { "CD", 0x4 },
16868 },
16869};
16870
16871static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16872 .num_items = 2,
16873 .items = {
16874 { "Mic", 0x1 },
16875 { "Line", 0x2 },
16876 },
16877};
Kailang Yang291702f2007-10-16 14:28:03 +020016878
Kailang Yang6dda9f42008-05-27 12:05:31 +020016879static struct hda_input_mux alc663_capture_source = {
16880 .num_items = 3,
16881 .items = {
16882 { "Mic", 0x0 },
16883 { "Front Mic", 0x1 },
16884 { "Line", 0x2 },
16885 },
16886};
16887
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016888#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016889static struct hda_input_mux alc272_nc10_capture_source = {
16890 .num_items = 16,
16891 .items = {
16892 { "Autoselect Mic", 0x0 },
16893 { "Internal Mic", 0x1 },
16894 { "In-0x02", 0x2 },
16895 { "In-0x03", 0x3 },
16896 { "In-0x04", 0x4 },
16897 { "In-0x05", 0x5 },
16898 { "In-0x06", 0x6 },
16899 { "In-0x07", 0x7 },
16900 { "In-0x08", 0x8 },
16901 { "In-0x09", 0x9 },
16902 { "In-0x0a", 0x0a },
16903 { "In-0x0b", 0x0b },
16904 { "In-0x0c", 0x0c },
16905 { "In-0x0d", 0x0d },
16906 { "In-0x0e", 0x0e },
16907 { "In-0x0f", 0x0f },
16908 },
16909};
16910#endif
16911
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016912/*
16913 * 2ch mode
16914 */
16915static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16916 { 2, NULL }
16917};
16918
16919/*
16920 * 2ch mode
16921 */
16922static struct hda_verb alc662_3ST_ch2_init[] = {
16923 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16924 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16925 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16926 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16927 { } /* end */
16928};
16929
16930/*
16931 * 6ch mode
16932 */
16933static struct hda_verb alc662_3ST_ch6_init[] = {
16934 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16935 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16936 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16937 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16938 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16939 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16940 { } /* end */
16941};
16942
16943static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16944 { 2, alc662_3ST_ch2_init },
16945 { 6, alc662_3ST_ch6_init },
16946};
16947
16948/*
16949 * 2ch mode
16950 */
16951static struct hda_verb alc662_sixstack_ch6_init[] = {
16952 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16953 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16954 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16955 { } /* end */
16956};
16957
16958/*
16959 * 6ch mode
16960 */
16961static struct hda_verb alc662_sixstack_ch8_init[] = {
16962 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16963 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16964 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16965 { } /* end */
16966};
16967
16968static struct hda_channel_mode alc662_5stack_modes[2] = {
16969 { 2, alc662_sixstack_ch6_init },
16970 { 6, alc662_sixstack_ch8_init },
16971};
16972
16973/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16974 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16975 */
16976
16977static struct snd_kcontrol_new alc662_base_mixer[] = {
16978 /* output mixer control */
16979 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016980 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016981 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016982 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016983 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16984 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016985 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16986 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016987 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16988
16989 /*Input mixer control */
16990 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16991 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16992 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16993 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16994 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16995 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16996 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16997 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016998 { } /* end */
16999};
17000
17001static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17002 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017003 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017004 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17005 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17006 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17007 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17008 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17009 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17010 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17011 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17012 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017013 { } /* end */
17014};
17015
17016static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17017 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017018 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017019 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017020 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017021 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17022 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017023 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17024 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017025 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17026 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17027 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17028 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17029 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17030 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17031 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17032 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17033 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017034 { } /* end */
17035};
17036
17037static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17038 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17039 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017040 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17041 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017042 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17043 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17044 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17045 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17046 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017047 { } /* end */
17048};
17049
Kailang Yang291702f2007-10-16 14:28:03 +020017050static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017051 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17052 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017053
17054 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17055 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17056 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17057
17058 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17059 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17060 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17061 { } /* end */
17062};
17063
Kailang Yang8c427222008-01-10 13:03:59 +010017064static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017065 ALC262_HIPPO_MASTER_SWITCH,
17066 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017067 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017068 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17069 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017070 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17071 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17072 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17073 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17074 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17075 { } /* end */
17076};
17077
Kailang Yangf1d4e282008-08-26 14:03:29 +020017078static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17079 .ops = &snd_hda_bind_vol,
17080 .values = {
17081 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17082 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17083 0
17084 },
17085};
17086
17087static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17088 .ops = &snd_hda_bind_sw,
17089 .values = {
17090 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17091 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17092 0
17093 },
17094};
17095
Kailang Yang6dda9f42008-05-27 12:05:31 +020017096static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017097 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17098 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17099 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17100 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17101 { } /* end */
17102};
17103
17104static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17105 .ops = &snd_hda_bind_sw,
17106 .values = {
17107 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17108 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17109 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17110 0
17111 },
17112};
17113
17114static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17115 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17116 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17117 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17118 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17119 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17120 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17121
17122 { } /* end */
17123};
17124
17125static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17126 .ops = &snd_hda_bind_sw,
17127 .values = {
17128 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17129 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17130 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17131 0
17132 },
17133};
17134
17135static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17136 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17137 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17138 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17139 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17140 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17141 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17142 { } /* end */
17143};
17144
17145static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017146 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17147 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017148 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
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("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17152 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17153 { } /* end */
17154};
17155
17156static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17157 .ops = &snd_hda_bind_vol,
17158 .values = {
17159 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17160 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17161 0
17162 },
17163};
17164
17165static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17166 .ops = &snd_hda_bind_sw,
17167 .values = {
17168 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17169 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17170 0
17171 },
17172};
17173
17174static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17175 HDA_BIND_VOL("Master Playback Volume",
17176 &alc663_asus_two_bind_master_vol),
17177 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17178 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017179 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17180 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17181 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017182 { } /* end */
17183};
17184
17185static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17186 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17187 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17188 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17189 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17190 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17191 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017192 { } /* end */
17193};
17194
17195static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17196 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17197 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17198 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17199 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17200 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17201
17202 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17203 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17204 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17205 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17206 { } /* end */
17207};
17208
17209static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17210 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17211 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17212 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17213
17214 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17215 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17216 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17217 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17218 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17219 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17220 { } /* end */
17221};
17222
Kailang Yangebb83ee2009-12-17 12:23:00 +010017223static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17224 .ops = &snd_hda_bind_sw,
17225 .values = {
17226 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17227 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17228 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17229 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17230 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17231 0
17232 },
17233};
17234
17235static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17236 .ops = &snd_hda_bind_sw,
17237 .values = {
17238 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17239 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17240 0
17241 },
17242};
17243
17244static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17245 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17246 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17247 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17248 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17249 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17250 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17251 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17252 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17253 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17254 { } /* end */
17255};
17256
17257static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17258 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17259 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17260 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17261 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17262 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17263 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17264 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17265 { } /* end */
17266};
17267
17268
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017269static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17270 {
17271 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17272 .name = "Channel Mode",
17273 .info = alc_ch_mode_info,
17274 .get = alc_ch_mode_get,
17275 .put = alc_ch_mode_put,
17276 },
17277 { } /* end */
17278};
17279
17280static struct hda_verb alc662_init_verbs[] = {
17281 /* ADC: mute amp left and right */
17282 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17283 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017284
Kailang Yangb60dd392007-09-20 12:50:29 +020017285 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17286 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17287 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17288 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17289 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17290 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017291
17292 /* Front Pin: output 0 (0x0c) */
17293 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17294 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17295
17296 /* Rear Pin: output 1 (0x0d) */
17297 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17298 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17299
17300 /* CLFE Pin: output 2 (0x0e) */
17301 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17302 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17303
17304 /* Mic (rear) pin: input vref at 80% */
17305 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17306 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17307 /* Front Mic pin: input vref at 80% */
17308 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17309 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17310 /* Line In pin: input */
17311 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17312 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17313 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17314 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17315 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17316 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17317 /* CD pin widget for input */
17318 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17319
17320 /* FIXME: use matrix-type input source selection */
17321 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17322 /* Input mixer */
17323 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017324 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017325
17326 /* always trun on EAPD */
17327 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17328 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17329
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017330 { }
17331};
17332
Kailang Yangcec27c82010-02-04 14:18:18 +010017333static struct hda_verb alc663_init_verbs[] = {
17334 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17335 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17336 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17337 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17338 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17339 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17340 { }
17341};
17342
17343static struct hda_verb alc272_init_verbs[] = {
17344 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17345 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17346 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17347 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17348 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17349 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17350 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17351 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17352 { }
17353};
17354
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017355static struct hda_verb alc662_sue_init_verbs[] = {
17356 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17357 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017358 {}
17359};
17360
17361static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17362 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17363 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17364 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017365};
17366
Kailang Yang8c427222008-01-10 13:03:59 +010017367/* Set Unsolicited Event*/
17368static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17369 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17370 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17371 {}
17372};
17373
Kailang Yang6dda9f42008-05-27 12:05:31 +020017374static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017375 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17376 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017377 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17378 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017379 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17380 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17381 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017382 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17383 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17384 {}
17385};
17386
Kailang Yangf1d4e282008-08-26 14:03:29 +020017387static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17388 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17389 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17390 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17391 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17392 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17393 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17394 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17395 {}
17396};
17397
17398static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17399 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17400 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17401 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17402 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17403 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17404 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17405 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17406 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17407 {}
17408};
17409
17410static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17411 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17412 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17413 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17414 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17415 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17416 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17417 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17418 {}
17419};
17420
17421static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17422 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17423 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17424 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17425 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17426 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17427 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17428 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17429 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17430 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17431 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17432 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17433 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17434 {}
17435};
17436
17437static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17438 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17439 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17440 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17441 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17442 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17443 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17444 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17445 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17446 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17447 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17448 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17449 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17450 {}
17451};
17452
Kailang Yang6dda9f42008-05-27 12:05:31 +020017453static struct hda_verb alc663_g71v_init_verbs[] = {
17454 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17455 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17456 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17457
17458 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17459 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17460 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17461
17462 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17463 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17464 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17465 {}
17466};
17467
17468static struct hda_verb alc663_g50v_init_verbs[] = {
17469 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17470 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17471 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17472
17473 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17474 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17475 {}
17476};
17477
Kailang Yangf1d4e282008-08-26 14:03:29 +020017478static struct hda_verb alc662_ecs_init_verbs[] = {
17479 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17480 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17481 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17482 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17483 {}
17484};
17485
Kailang Yang622e84c2009-04-21 07:39:04 +020017486static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17487 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17488 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17489 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17490 {0x16, 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 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17497 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17498 {}
17499};
17500
17501static struct hda_verb alc272_dell_init_verbs[] = {
17502 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17503 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17504 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17505 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17506 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17507 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17508 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17509 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17510 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17511 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17512 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17513 {}
17514};
17515
Kailang Yangebb83ee2009-12-17 12:23:00 +010017516static struct hda_verb alc663_mode7_init_verbs[] = {
17517 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17518 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17519 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17520 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17521 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17522 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17523 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17524 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17525 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17526 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17527 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17528 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17529 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17530 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17531 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17532 {}
17533};
17534
17535static struct hda_verb alc663_mode8_init_verbs[] = {
17536 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17539 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17540 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17541 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17542 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17543 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17544 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17545 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17546 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17547 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17548 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17549 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17550 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17551 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17552 {}
17553};
17554
Kailang Yangf1d4e282008-08-26 14:03:29 +020017555static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17556 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17557 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17558 { } /* end */
17559};
17560
Kailang Yang622e84c2009-04-21 07:39:04 +020017561static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17562 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17563 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17564 { } /* end */
17565};
17566
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017567static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17568{
17569 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017570 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017571
Wu Fengguang864f92b2009-11-18 12:38:02 +080017572 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017573 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017574
Takashi Iwai47fd8302007-08-10 17:11:07 +020017575 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17576 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017577}
17578
17579static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17580{
17581 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017582 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017583
Wu Fengguang864f92b2009-11-18 12:38:02 +080017584 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017585 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017586
Takashi Iwai47fd8302007-08-10 17:11:07 +020017587 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17588 HDA_AMP_MUTE, bits);
17589 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17590 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017591}
17592
17593static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17594 unsigned int res)
17595{
17596 if ((res >> 26) == ALC880_HP_EVENT)
17597 alc662_lenovo_101e_all_automute(codec);
17598 if ((res >> 26) == ALC880_FRONT_EVENT)
17599 alc662_lenovo_101e_ispeaker_automute(codec);
17600}
17601
Kailang Yang291702f2007-10-16 14:28:03 +020017602/* unsolicited event for HP jack sensing */
17603static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17604 unsigned int res)
17605{
Kailang Yang291702f2007-10-16 14:28:03 +020017606 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017607 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020017608 else
17609 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020017610}
17611
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017612static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017613{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017614 struct alc_spec *spec = codec->spec;
17615
17616 alc262_hippo1_setup(codec);
17617 spec->ext_mic.pin = 0x18;
17618 spec->ext_mic.mux_idx = 0;
17619 spec->int_mic.pin = 0x19;
17620 spec->int_mic.mux_idx = 1;
17621 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017622}
17623
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017624static void alc662_eeepc_inithook(struct hda_codec *codec)
17625{
17626 alc262_hippo_automute(codec);
17627 alc_mic_automute(codec);
17628}
17629
17630static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017631{
Takashi Iwai42171c12009-05-08 14:11:43 +020017632 struct alc_spec *spec = codec->spec;
17633
17634 spec->autocfg.hp_pins[0] = 0x14;
17635 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010017636}
17637
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017638#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
17639
Kailang Yang6dda9f42008-05-27 12:05:31 +020017640static void alc663_m51va_speaker_automute(struct hda_codec *codec)
17641{
17642 unsigned int present;
17643 unsigned char bits;
17644
Wu Fengguang864f92b2009-11-18 12:38:02 +080017645 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017646 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017647 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017648 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017649 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017650 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017651}
17652
17653static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
17654{
17655 unsigned int present;
17656 unsigned char bits;
17657
Wu Fengguang864f92b2009-11-18 12:38:02 +080017658 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017659 bits = present ? HDA_AMP_MUTE : 0;
17660 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017661 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017662 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017663 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017664 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017665 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017666 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017667 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017668}
17669
17670static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
17671{
17672 unsigned int present;
17673 unsigned char bits;
17674
Wu Fengguang864f92b2009-11-18 12:38:02 +080017675 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017676 bits = present ? HDA_AMP_MUTE : 0;
17677 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017678 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017679 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017680 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017681 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017682 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017683 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017684 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017685}
17686
17687static void alc662_f5z_speaker_automute(struct hda_codec *codec)
17688{
17689 unsigned int present;
17690 unsigned char bits;
17691
Wu Fengguang864f92b2009-11-18 12:38:02 +080017692 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017693 bits = present ? 0 : PIN_OUT;
17694 snd_hda_codec_write(codec, 0x14, 0,
17695 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
17696}
17697
17698static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
17699{
17700 unsigned int present1, present2;
17701
Wu Fengguang864f92b2009-11-18 12:38:02 +080017702 present1 = snd_hda_jack_detect(codec, 0x21);
17703 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017704
17705 if (present1 || present2) {
17706 snd_hda_codec_write_cache(codec, 0x14, 0,
17707 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17708 } else {
17709 snd_hda_codec_write_cache(codec, 0x14, 0,
17710 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17711 }
17712}
17713
17714static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
17715{
17716 unsigned int present1, present2;
17717
Wu Fengguang864f92b2009-11-18 12:38:02 +080017718 present1 = snd_hda_jack_detect(codec, 0x1b);
17719 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017720
17721 if (present1 || present2) {
17722 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017723 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017724 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017725 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017726 } else {
17727 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017728 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017729 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017730 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017731 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020017732}
17733
Kailang Yangebb83ee2009-12-17 12:23:00 +010017734static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
17735{
17736 unsigned int present1, present2;
17737
17738 present1 = snd_hda_codec_read(codec, 0x1b, 0,
17739 AC_VERB_GET_PIN_SENSE, 0)
17740 & AC_PINSENSE_PRESENCE;
17741 present2 = snd_hda_codec_read(codec, 0x21, 0,
17742 AC_VERB_GET_PIN_SENSE, 0)
17743 & AC_PINSENSE_PRESENCE;
17744
17745 if (present1 || present2) {
17746 snd_hda_codec_write_cache(codec, 0x14, 0,
17747 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17748 snd_hda_codec_write_cache(codec, 0x17, 0,
17749 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17750 } else {
17751 snd_hda_codec_write_cache(codec, 0x14, 0,
17752 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17753 snd_hda_codec_write_cache(codec, 0x17, 0,
17754 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17755 }
17756}
17757
17758static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
17759{
17760 unsigned int present1, present2;
17761
17762 present1 = snd_hda_codec_read(codec, 0x21, 0,
17763 AC_VERB_GET_PIN_SENSE, 0)
17764 & AC_PINSENSE_PRESENCE;
17765 present2 = snd_hda_codec_read(codec, 0x15, 0,
17766 AC_VERB_GET_PIN_SENSE, 0)
17767 & AC_PINSENSE_PRESENCE;
17768
17769 if (present1 || present2) {
17770 snd_hda_codec_write_cache(codec, 0x14, 0,
17771 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17772 snd_hda_codec_write_cache(codec, 0x17, 0,
17773 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17774 } else {
17775 snd_hda_codec_write_cache(codec, 0x14, 0,
17776 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17777 snd_hda_codec_write_cache(codec, 0x17, 0,
17778 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17779 }
17780}
17781
Kailang Yang6dda9f42008-05-27 12:05:31 +020017782static void alc663_m51va_unsol_event(struct hda_codec *codec,
17783 unsigned int res)
17784{
17785 switch (res >> 26) {
17786 case ALC880_HP_EVENT:
17787 alc663_m51va_speaker_automute(codec);
17788 break;
17789 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017790 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017791 break;
17792 }
17793}
17794
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017795static void alc663_m51va_setup(struct hda_codec *codec)
17796{
17797 struct alc_spec *spec = codec->spec;
17798 spec->ext_mic.pin = 0x18;
17799 spec->ext_mic.mux_idx = 0;
17800 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017801 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017802 spec->auto_mic = 1;
17803}
17804
Kailang Yang6dda9f42008-05-27 12:05:31 +020017805static void alc663_m51va_inithook(struct hda_codec *codec)
17806{
17807 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017808 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017809}
17810
Kailang Yangf1d4e282008-08-26 14:03:29 +020017811/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017812#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017813
17814static void alc663_mode1_setup(struct hda_codec *codec)
17815{
17816 struct alc_spec *spec = codec->spec;
17817 spec->ext_mic.pin = 0x18;
17818 spec->ext_mic.mux_idx = 0;
17819 spec->int_mic.pin = 0x19;
17820 spec->int_mic.mux_idx = 1;
17821 spec->auto_mic = 1;
17822}
17823
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017824#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017825
Kailang Yangf1d4e282008-08-26 14:03:29 +020017826/* ***************** Mode2 ******************************/
17827static void alc662_mode2_unsol_event(struct hda_codec *codec,
17828 unsigned int res)
17829{
17830 switch (res >> 26) {
17831 case ALC880_HP_EVENT:
17832 alc662_f5z_speaker_automute(codec);
17833 break;
17834 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017835 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017836 break;
17837 }
17838}
17839
Kailang Yangebb83ee2009-12-17 12:23:00 +010017840#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017841
Kailang Yangf1d4e282008-08-26 14:03:29 +020017842static void alc662_mode2_inithook(struct hda_codec *codec)
17843{
17844 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017845 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017846}
17847/* ***************** Mode3 ******************************/
17848static void alc663_mode3_unsol_event(struct hda_codec *codec,
17849 unsigned int res)
17850{
17851 switch (res >> 26) {
17852 case ALC880_HP_EVENT:
17853 alc663_two_hp_m1_speaker_automute(codec);
17854 break;
17855 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017856 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017857 break;
17858 }
17859}
17860
Kailang Yangebb83ee2009-12-17 12:23:00 +010017861#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017862
Kailang Yangf1d4e282008-08-26 14:03:29 +020017863static void alc663_mode3_inithook(struct hda_codec *codec)
17864{
17865 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017866 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017867}
17868/* ***************** Mode4 ******************************/
17869static void alc663_mode4_unsol_event(struct hda_codec *codec,
17870 unsigned int res)
17871{
17872 switch (res >> 26) {
17873 case ALC880_HP_EVENT:
17874 alc663_21jd_two_speaker_automute(codec);
17875 break;
17876 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017877 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017878 break;
17879 }
17880}
17881
Kailang Yangebb83ee2009-12-17 12:23:00 +010017882#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017883
Kailang Yangf1d4e282008-08-26 14:03:29 +020017884static void alc663_mode4_inithook(struct hda_codec *codec)
17885{
17886 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017887 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017888}
17889/* ***************** Mode5 ******************************/
17890static void alc663_mode5_unsol_event(struct hda_codec *codec,
17891 unsigned int res)
17892{
17893 switch (res >> 26) {
17894 case ALC880_HP_EVENT:
17895 alc663_15jd_two_speaker_automute(codec);
17896 break;
17897 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017898 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017899 break;
17900 }
17901}
17902
Kailang Yangebb83ee2009-12-17 12:23:00 +010017903#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017904
Kailang Yangf1d4e282008-08-26 14:03:29 +020017905static void alc663_mode5_inithook(struct hda_codec *codec)
17906{
17907 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017908 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017909}
17910/* ***************** Mode6 ******************************/
17911static void alc663_mode6_unsol_event(struct hda_codec *codec,
17912 unsigned int res)
17913{
17914 switch (res >> 26) {
17915 case ALC880_HP_EVENT:
17916 alc663_two_hp_m2_speaker_automute(codec);
17917 break;
17918 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017919 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017920 break;
17921 }
17922}
17923
Kailang Yangebb83ee2009-12-17 12:23:00 +010017924#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017925
Kailang Yangf1d4e282008-08-26 14:03:29 +020017926static void alc663_mode6_inithook(struct hda_codec *codec)
17927{
17928 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017929 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017930}
17931
Kailang Yangebb83ee2009-12-17 12:23:00 +010017932/* ***************** Mode7 ******************************/
17933static void alc663_mode7_unsol_event(struct hda_codec *codec,
17934 unsigned int res)
17935{
17936 switch (res >> 26) {
17937 case ALC880_HP_EVENT:
17938 alc663_two_hp_m7_speaker_automute(codec);
17939 break;
17940 case ALC880_MIC_EVENT:
17941 alc_mic_automute(codec);
17942 break;
17943 }
17944}
17945
17946#define alc663_mode7_setup alc663_mode1_setup
17947
17948static void alc663_mode7_inithook(struct hda_codec *codec)
17949{
17950 alc663_two_hp_m7_speaker_automute(codec);
17951 alc_mic_automute(codec);
17952}
17953
17954/* ***************** Mode8 ******************************/
17955static void alc663_mode8_unsol_event(struct hda_codec *codec,
17956 unsigned int res)
17957{
17958 switch (res >> 26) {
17959 case ALC880_HP_EVENT:
17960 alc663_two_hp_m8_speaker_automute(codec);
17961 break;
17962 case ALC880_MIC_EVENT:
17963 alc_mic_automute(codec);
17964 break;
17965 }
17966}
17967
17968#define alc663_mode8_setup alc663_m51va_setup
17969
17970static void alc663_mode8_inithook(struct hda_codec *codec)
17971{
17972 alc663_two_hp_m8_speaker_automute(codec);
17973 alc_mic_automute(codec);
17974}
17975
Kailang Yang6dda9f42008-05-27 12:05:31 +020017976static void alc663_g71v_hp_automute(struct hda_codec *codec)
17977{
17978 unsigned int present;
17979 unsigned char bits;
17980
Wu Fengguang864f92b2009-11-18 12:38:02 +080017981 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017982 bits = present ? HDA_AMP_MUTE : 0;
17983 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17984 HDA_AMP_MUTE, bits);
17985 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17986 HDA_AMP_MUTE, bits);
17987}
17988
17989static void alc663_g71v_front_automute(struct hda_codec *codec)
17990{
17991 unsigned int present;
17992 unsigned char bits;
17993
Wu Fengguang864f92b2009-11-18 12:38:02 +080017994 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017995 bits = present ? HDA_AMP_MUTE : 0;
17996 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17997 HDA_AMP_MUTE, bits);
17998}
17999
18000static void alc663_g71v_unsol_event(struct hda_codec *codec,
18001 unsigned int res)
18002{
18003 switch (res >> 26) {
18004 case ALC880_HP_EVENT:
18005 alc663_g71v_hp_automute(codec);
18006 break;
18007 case ALC880_FRONT_EVENT:
18008 alc663_g71v_front_automute(codec);
18009 break;
18010 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018011 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018012 break;
18013 }
18014}
18015
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018016#define alc663_g71v_setup alc663_m51va_setup
18017
Kailang Yang6dda9f42008-05-27 12:05:31 +020018018static void alc663_g71v_inithook(struct hda_codec *codec)
18019{
18020 alc663_g71v_front_automute(codec);
18021 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018022 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018023}
18024
18025static void alc663_g50v_unsol_event(struct hda_codec *codec,
18026 unsigned int res)
18027{
18028 switch (res >> 26) {
18029 case ALC880_HP_EVENT:
18030 alc663_m51va_speaker_automute(codec);
18031 break;
18032 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018033 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018034 break;
18035 }
18036}
18037
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018038#define alc663_g50v_setup alc663_m51va_setup
18039
Kailang Yang6dda9f42008-05-27 12:05:31 +020018040static void alc663_g50v_inithook(struct hda_codec *codec)
18041{
18042 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018043 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018044}
18045
Kailang Yangf1d4e282008-08-26 14:03:29 +020018046static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18047 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018048 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018049
18050 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
18051 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18052 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18053
18054 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18055 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18056 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18057 { } /* end */
18058};
18059
Chris Pockelé9541ba12009-05-12 08:08:53 +020018060static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18061 /* Master Playback automatically created from Speaker and Headphone */
18062 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18063 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18064 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18065 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18066
18067 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18068 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18069 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18070
18071 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18072 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18073 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18074 { } /* end */
18075};
18076
Takashi Iwaicb53c622007-08-10 17:21:45 +020018077#ifdef CONFIG_SND_HDA_POWER_SAVE
18078#define alc662_loopbacks alc880_loopbacks
18079#endif
18080
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018081
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018082/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018083#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18084#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18085#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18086#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18087
18088/*
18089 * configuration and preset
18090 */
18091static const char *alc662_models[ALC662_MODEL_LAST] = {
18092 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18093 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18094 [ALC662_3ST_6ch] = "3stack-6ch",
18095 [ALC662_5ST_DIG] = "6stack-dig",
18096 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018097 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018098 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018099 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018100 [ALC663_ASUS_M51VA] = "m51va",
18101 [ALC663_ASUS_G71V] = "g71v",
18102 [ALC663_ASUS_H13] = "h13",
18103 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018104 [ALC663_ASUS_MODE1] = "asus-mode1",
18105 [ALC662_ASUS_MODE2] = "asus-mode2",
18106 [ALC663_ASUS_MODE3] = "asus-mode3",
18107 [ALC663_ASUS_MODE4] = "asus-mode4",
18108 [ALC663_ASUS_MODE5] = "asus-mode5",
18109 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018110 [ALC663_ASUS_MODE7] = "asus-mode7",
18111 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018112 [ALC272_DELL] = "dell",
18113 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018114 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018115 [ALC662_AUTO] = "auto",
18116};
18117
18118static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018119 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018120 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18121 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018122 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18123 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018124 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018125 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18126 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18127 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18128 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018129 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18130 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018131 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018132 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18133 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18134 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18135 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18136 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018137 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018138 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18139 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018140 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18141 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18142 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18143 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018144 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018145 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18146 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18147 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018148 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18149 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18150 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18151 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018152 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018153 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18154 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018155 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018156 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18157 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18158 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018159 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018160 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018161 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18162 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018163 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18164 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18165 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018166 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018167 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18168 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018169 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018170 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018171 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018172 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18173 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18174 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018175 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018176 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18177 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018178 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018179 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018180 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018181 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018182 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18183 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018184 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018185 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018186 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18187 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018188 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018189 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018190 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018191 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018192 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018193 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018194 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18195 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018196 {}
18197};
18198
18199static struct alc_config_preset alc662_presets[] = {
18200 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018201 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018202 .init_verbs = { alc662_init_verbs },
18203 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18204 .dac_nids = alc662_dac_nids,
18205 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018206 .dig_in_nid = ALC662_DIGIN_NID,
18207 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18208 .channel_mode = alc662_3ST_2ch_modes,
18209 .input_mux = &alc662_capture_source,
18210 },
18211 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018212 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018213 .init_verbs = { alc662_init_verbs },
18214 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18215 .dac_nids = alc662_dac_nids,
18216 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018217 .dig_in_nid = ALC662_DIGIN_NID,
18218 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18219 .channel_mode = alc662_3ST_6ch_modes,
18220 .need_dac_fix = 1,
18221 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018222 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018223 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018224 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018225 .init_verbs = { alc662_init_verbs },
18226 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18227 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018228 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18229 .channel_mode = alc662_3ST_6ch_modes,
18230 .need_dac_fix = 1,
18231 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018232 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018233 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018234 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018235 .init_verbs = { alc662_init_verbs },
18236 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18237 .dac_nids = alc662_dac_nids,
18238 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018239 .dig_in_nid = ALC662_DIGIN_NID,
18240 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18241 .channel_mode = alc662_5stack_modes,
18242 .input_mux = &alc662_capture_source,
18243 },
18244 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018245 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018246 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18247 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18248 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018249 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18250 .channel_mode = alc662_3ST_2ch_modes,
18251 .input_mux = &alc662_lenovo_101e_capture_source,
18252 .unsol_event = alc662_lenovo_101e_unsol_event,
18253 .init_hook = alc662_lenovo_101e_all_automute,
18254 },
Kailang Yang291702f2007-10-16 14:28:03 +020018255 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018256 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018257 .init_verbs = { alc662_init_verbs,
18258 alc662_eeepc_sue_init_verbs },
18259 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18260 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018261 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18262 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018263 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018264 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018265 .init_hook = alc662_eeepc_inithook,
18266 },
Kailang Yang8c427222008-01-10 13:03:59 +010018267 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018268 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018269 alc662_chmode_mixer },
18270 .init_verbs = { alc662_init_verbs,
18271 alc662_eeepc_ep20_sue_init_verbs },
18272 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18273 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018274 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18275 .channel_mode = alc662_3ST_6ch_modes,
18276 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018277 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018278 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018279 .init_hook = alc662_eeepc_ep20_inithook,
18280 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018281 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018282 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018283 .init_verbs = { alc662_init_verbs,
18284 alc662_ecs_init_verbs },
18285 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18286 .dac_nids = alc662_dac_nids,
18287 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18288 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018289 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018290 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018291 .init_hook = alc662_eeepc_inithook,
18292 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018293 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018294 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018295 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18296 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18297 .dac_nids = alc662_dac_nids,
18298 .dig_out_nid = ALC662_DIGOUT_NID,
18299 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18300 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018301 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018302 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018303 .init_hook = alc663_m51va_inithook,
18304 },
18305 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018306 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018307 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18308 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18309 .dac_nids = alc662_dac_nids,
18310 .dig_out_nid = ALC662_DIGOUT_NID,
18311 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18312 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018313 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018314 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018315 .init_hook = alc663_g71v_inithook,
18316 },
18317 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018318 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018319 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18320 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18321 .dac_nids = alc662_dac_nids,
18322 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18323 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018324 .unsol_event = alc663_m51va_unsol_event,
18325 .init_hook = alc663_m51va_inithook,
18326 },
18327 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018328 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018329 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18330 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18331 .dac_nids = alc662_dac_nids,
18332 .dig_out_nid = ALC662_DIGOUT_NID,
18333 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18334 .channel_mode = alc662_3ST_6ch_modes,
18335 .input_mux = &alc663_capture_source,
18336 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018337 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018338 .init_hook = alc663_g50v_inithook,
18339 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018340 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018341 .mixers = { alc663_m51va_mixer },
18342 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018343 .init_verbs = { alc662_init_verbs,
18344 alc663_21jd_amic_init_verbs },
18345 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18346 .hp_nid = 0x03,
18347 .dac_nids = alc662_dac_nids,
18348 .dig_out_nid = ALC662_DIGOUT_NID,
18349 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18350 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018351 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018352 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018353 .init_hook = alc663_mode1_inithook,
18354 },
18355 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018356 .mixers = { alc662_1bjd_mixer },
18357 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018358 .init_verbs = { alc662_init_verbs,
18359 alc662_1bjd_amic_init_verbs },
18360 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18361 .dac_nids = alc662_dac_nids,
18362 .dig_out_nid = ALC662_DIGOUT_NID,
18363 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18364 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018365 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018366 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018367 .init_hook = alc662_mode2_inithook,
18368 },
18369 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018370 .mixers = { alc663_two_hp_m1_mixer },
18371 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018372 .init_verbs = { alc662_init_verbs,
18373 alc663_two_hp_amic_m1_init_verbs },
18374 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18375 .hp_nid = 0x03,
18376 .dac_nids = alc662_dac_nids,
18377 .dig_out_nid = ALC662_DIGOUT_NID,
18378 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18379 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018380 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018381 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018382 .init_hook = alc663_mode3_inithook,
18383 },
18384 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018385 .mixers = { alc663_asus_21jd_clfe_mixer },
18386 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018387 .init_verbs = { alc662_init_verbs,
18388 alc663_21jd_amic_init_verbs},
18389 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18390 .hp_nid = 0x03,
18391 .dac_nids = alc662_dac_nids,
18392 .dig_out_nid = ALC662_DIGOUT_NID,
18393 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18394 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018395 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018396 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018397 .init_hook = alc663_mode4_inithook,
18398 },
18399 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018400 .mixers = { alc663_asus_15jd_clfe_mixer },
18401 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018402 .init_verbs = { alc662_init_verbs,
18403 alc663_15jd_amic_init_verbs },
18404 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18405 .hp_nid = 0x03,
18406 .dac_nids = alc662_dac_nids,
18407 .dig_out_nid = ALC662_DIGOUT_NID,
18408 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18409 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018410 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018411 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018412 .init_hook = alc663_mode5_inithook,
18413 },
18414 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018415 .mixers = { alc663_two_hp_m2_mixer },
18416 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018417 .init_verbs = { alc662_init_verbs,
18418 alc663_two_hp_amic_m2_init_verbs },
18419 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18420 .hp_nid = 0x03,
18421 .dac_nids = alc662_dac_nids,
18422 .dig_out_nid = ALC662_DIGOUT_NID,
18423 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18424 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018425 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018426 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018427 .init_hook = alc663_mode6_inithook,
18428 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018429 [ALC663_ASUS_MODE7] = {
18430 .mixers = { alc663_mode7_mixer },
18431 .cap_mixer = alc662_auto_capture_mixer,
18432 .init_verbs = { alc662_init_verbs,
18433 alc663_mode7_init_verbs },
18434 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18435 .hp_nid = 0x03,
18436 .dac_nids = alc662_dac_nids,
18437 .dig_out_nid = ALC662_DIGOUT_NID,
18438 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18439 .channel_mode = alc662_3ST_2ch_modes,
18440 .unsol_event = alc663_mode7_unsol_event,
18441 .setup = alc663_mode7_setup,
18442 .init_hook = alc663_mode7_inithook,
18443 },
18444 [ALC663_ASUS_MODE8] = {
18445 .mixers = { alc663_mode8_mixer },
18446 .cap_mixer = alc662_auto_capture_mixer,
18447 .init_verbs = { alc662_init_verbs,
18448 alc663_mode8_init_verbs },
18449 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18450 .hp_nid = 0x03,
18451 .dac_nids = alc662_dac_nids,
18452 .dig_out_nid = ALC662_DIGOUT_NID,
18453 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18454 .channel_mode = alc662_3ST_2ch_modes,
18455 .unsol_event = alc663_mode8_unsol_event,
18456 .setup = alc663_mode8_setup,
18457 .init_hook = alc663_mode8_inithook,
18458 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018459 [ALC272_DELL] = {
18460 .mixers = { alc663_m51va_mixer },
18461 .cap_mixer = alc272_auto_capture_mixer,
18462 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18463 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18464 .dac_nids = alc662_dac_nids,
18465 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18466 .adc_nids = alc272_adc_nids,
18467 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18468 .capsrc_nids = alc272_capsrc_nids,
18469 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018470 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018471 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018472 .init_hook = alc663_m51va_inithook,
18473 },
18474 [ALC272_DELL_ZM1] = {
18475 .mixers = { alc663_m51va_mixer },
18476 .cap_mixer = alc662_auto_capture_mixer,
18477 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18478 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18479 .dac_nids = alc662_dac_nids,
18480 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18481 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018482 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018483 .capsrc_nids = alc662_capsrc_nids,
18484 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018485 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018486 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018487 .init_hook = alc663_m51va_inithook,
18488 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018489 [ALC272_SAMSUNG_NC10] = {
18490 .mixers = { alc272_nc10_mixer },
18491 .init_verbs = { alc662_init_verbs,
18492 alc663_21jd_amic_init_verbs },
18493 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18494 .dac_nids = alc272_dac_nids,
18495 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18496 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018497 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018498 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018499 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018500 .init_hook = alc663_mode4_inithook,
18501 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018502};
18503
18504
18505/*
18506 * BIOS auto configuration
18507 */
18508
Takashi Iwai7085ec12009-10-02 09:03:58 +020018509/* convert from MIX nid to DAC */
18510static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18511{
18512 if (nid == 0x0f)
18513 return 0x02;
18514 else if (nid >= 0x0c && nid <= 0x0e)
18515 return nid - 0x0c + 0x02;
18516 else
18517 return 0;
18518}
18519
18520/* get MIX nid connected to the given pin targeted to DAC */
18521static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18522 hda_nid_t dac)
18523{
18524 hda_nid_t mix[4];
18525 int i, num;
18526
18527 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18528 for (i = 0; i < num; i++) {
18529 if (alc662_mix_to_dac(mix[i]) == dac)
18530 return mix[i];
18531 }
18532 return 0;
18533}
18534
18535/* look for an empty DAC slot */
18536static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18537{
18538 struct alc_spec *spec = codec->spec;
18539 hda_nid_t srcs[5];
18540 int i, j, num;
18541
18542 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18543 if (num < 0)
18544 return 0;
18545 for (i = 0; i < num; i++) {
18546 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18547 if (!nid)
18548 continue;
18549 for (j = 0; j < spec->multiout.num_dacs; j++)
18550 if (spec->multiout.dac_nids[j] == nid)
18551 break;
18552 if (j >= spec->multiout.num_dacs)
18553 return nid;
18554 }
18555 return 0;
18556}
18557
18558/* fill in the dac_nids table from the parsed pin configuration */
18559static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18560 const struct auto_pin_cfg *cfg)
18561{
18562 struct alc_spec *spec = codec->spec;
18563 int i;
18564 hda_nid_t dac;
18565
18566 spec->multiout.dac_nids = spec->private_dac_nids;
18567 for (i = 0; i < cfg->line_outs; i++) {
18568 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18569 if (!dac)
18570 continue;
18571 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18572 }
18573 return 0;
18574}
18575
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018576static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018577 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018578{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018579 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018580 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18581}
18582
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018583static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018584 hda_nid_t nid, unsigned int chs)
18585{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018586 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018587 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18588}
18589
18590#define alc662_add_stereo_vol(spec, pfx, nid) \
18591 alc662_add_vol_ctl(spec, pfx, nid, 3)
18592#define alc662_add_stereo_sw(spec, pfx, nid) \
18593 alc662_add_sw_ctl(spec, pfx, nid, 3)
18594
18595/* add playback controls from the parsed DAC table */
18596static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18597 const struct auto_pin_cfg *cfg)
18598{
18599 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018600 static const char *chname[4] = {
18601 "Front", "Surround", NULL /*CLFE*/, "Side"
18602 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018603 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018604 int i, err;
18605
18606 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018607 nid = spec->multiout.dac_nids[i];
18608 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018609 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018610 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
18611 if (!mix)
18612 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018613 if (i == 2) {
18614 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018615 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018616 if (err < 0)
18617 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018618 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018619 if (err < 0)
18620 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018621 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018622 if (err < 0)
18623 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018624 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018625 if (err < 0)
18626 return err;
18627 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018628 const char *pfx;
18629 if (cfg->line_outs == 1 &&
18630 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018631 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018632 pfx = "Speaker";
18633 else
18634 pfx = "PCM";
18635 } else
18636 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018637 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018638 if (err < 0)
18639 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018640 if (cfg->line_outs == 1 &&
18641 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
18642 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020018643 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018644 if (err < 0)
18645 return err;
18646 }
18647 }
18648 return 0;
18649}
18650
18651/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018652/* return DAC nid if any new DAC is assigned */
18653static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018654 const char *pfx)
18655{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018656 struct alc_spec *spec = codec->spec;
18657 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018658 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018659
18660 if (!pin)
18661 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018662 nid = alc662_look_for_dac(codec, pin);
18663 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018664 /* the corresponding DAC is already occupied */
18665 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18666 return 0; /* no way */
18667 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018668 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018669 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18670 }
18671
18672 mix = alc662_dac_to_mix(codec, pin, nid);
18673 if (!mix)
18674 return 0;
18675 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
18676 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018677 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018678 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
18679 if (err < 0)
18680 return err;
18681 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018682}
18683
18684/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018685#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018686 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018687
18688static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
18689 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018690 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018691{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018692 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020018693 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018694
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018695 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018696 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018697 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
18698 if (num <= 1)
18699 return;
18700 for (i = 0; i < num; i++) {
18701 if (alc662_mix_to_dac(srcs[i]) != dac)
18702 continue;
18703 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18704 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018705 }
18706}
18707
18708static void alc662_auto_init_multi_out(struct hda_codec *codec)
18709{
18710 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018711 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018712 int i;
18713
18714 for (i = 0; i <= HDA_SIDE; i++) {
18715 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18716 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020018717 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018718 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018719 }
18720}
18721
18722static void alc662_auto_init_hp_out(struct hda_codec *codec)
18723{
18724 struct alc_spec *spec = codec->spec;
18725 hda_nid_t pin;
18726
18727 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018728 if (pin)
18729 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
18730 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018731 pin = spec->autocfg.speaker_pins[0];
18732 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018733 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
18734 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018735}
18736
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018737#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
18738
18739static void alc662_auto_init_analog_input(struct hda_codec *codec)
18740{
18741 struct alc_spec *spec = codec->spec;
18742 int i;
18743
18744 for (i = 0; i < AUTO_PIN_LAST; i++) {
18745 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020018746 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010018747 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010018748 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010018749 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018750 snd_hda_codec_write(codec, nid, 0,
18751 AC_VERB_SET_AMP_GAIN_MUTE,
18752 AMP_OUT_MUTE);
18753 }
18754 }
18755}
18756
Takashi Iwaif511b012008-08-15 16:46:42 +020018757#define alc662_auto_init_input_src alc882_auto_init_input_src
18758
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018759static int alc662_parse_auto_config(struct hda_codec *codec)
18760{
18761 struct alc_spec *spec = codec->spec;
18762 int err;
18763 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
18764
18765 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18766 alc662_ignore);
18767 if (err < 0)
18768 return err;
18769 if (!spec->autocfg.line_outs)
18770 return 0; /* can't find valid BIOS pin config */
18771
Takashi Iwai7085ec12009-10-02 09:03:58 +020018772 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018773 if (err < 0)
18774 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018775 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018776 if (err < 0)
18777 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018778 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018779 spec->autocfg.speaker_pins[0],
18780 "Speaker");
18781 if (err < 0)
18782 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018783 if (err)
18784 spec->multiout.extra_out_nid[0] = err;
18785 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018786 "Headphone");
18787 if (err < 0)
18788 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018789 if (err)
18790 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018791 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018792 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018793 return err;
18794
18795 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18796
Takashi Iwai757899a2010-07-30 10:48:14 +020018797 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018798
Takashi Iwai603c4012008-07-30 15:01:44 +020018799 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018800 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018801
18802 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018803 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018804
Kailang Yangcec27c82010-02-04 14:18:18 +010018805 add_verb(spec, alc662_init_verbs);
18806 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018807 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010018808 add_verb(spec, alc663_init_verbs);
18809
18810 if (codec->vendor_id == 0x10ec0272)
18811 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018812
18813 err = alc_auto_add_mic_boost(codec);
18814 if (err < 0)
18815 return err;
18816
Kailang Yang6227cdc2010-02-25 08:36:52 +010018817 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18818 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18819 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18820 else
18821 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018822
Takashi Iwai8c872862007-06-19 12:11:16 +020018823 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018824}
18825
18826/* additional initialization for auto-configuration model */
18827static void alc662_auto_init(struct hda_codec *codec)
18828{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018829 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018830 alc662_auto_init_multi_out(codec);
18831 alc662_auto_init_hp_out(codec);
18832 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018833 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020018834 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018835 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018836 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018837}
18838
18839static int patch_alc662(struct hda_codec *codec)
18840{
18841 struct alc_spec *spec;
18842 int err, board_config;
18843
18844 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18845 if (!spec)
18846 return -ENOMEM;
18847
18848 codec->spec = spec;
18849
Kailang Yangda00c242010-03-19 11:23:45 +010018850 alc_auto_parse_customize_define(codec);
18851
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018852 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18853
Kailang Yangc027ddc2010-03-19 11:33:06 +010018854 if (alc_read_coef_idx(codec, 0) == 0x8020)
18855 alc_codec_rename(codec, "ALC661");
18856 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
18857 codec->bus->pci->subsystem_vendor == 0x1025 &&
18858 spec->cdefine.platform_type == 1)
18859 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010018860
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018861 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18862 alc662_models,
18863 alc662_cfg_tbl);
18864 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018865 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18866 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018867 board_config = ALC662_AUTO;
18868 }
18869
18870 if (board_config == ALC662_AUTO) {
18871 /* automatic parse from the BIOS config */
18872 err = alc662_parse_auto_config(codec);
18873 if (err < 0) {
18874 alc_free(codec);
18875 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018876 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018877 printk(KERN_INFO
18878 "hda_codec: Cannot set up configuration "
18879 "from BIOS. Using base mode...\n");
18880 board_config = ALC662_3ST_2ch_DIG;
18881 }
18882 }
18883
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018884 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020018885 err = snd_hda_attach_beep_device(codec, 0x1);
18886 if (err < 0) {
18887 alc_free(codec);
18888 return err;
18889 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018890 }
18891
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018892 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018893 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018894
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018895 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18896 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18897
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018898 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18899 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18900
Takashi Iwaidd704692009-08-11 08:45:11 +020018901 if (!spec->adc_nids) {
18902 spec->adc_nids = alc662_adc_nids;
18903 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18904 }
18905 if (!spec->capsrc_nids)
18906 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018907
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018908 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018909 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018910
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018911 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010018912 switch (codec->vendor_id) {
18913 case 0x10ec0662:
18914 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18915 break;
18916 case 0x10ec0272:
18917 case 0x10ec0663:
18918 case 0x10ec0665:
18919 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18920 break;
18921 case 0x10ec0273:
18922 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18923 break;
18924 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018925 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018926 spec->vmaster_nid = 0x02;
18927
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018928 codec->patch_ops = alc_patch_ops;
18929 if (board_config == ALC662_AUTO)
18930 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018931#ifdef CONFIG_SND_HDA_POWER_SAVE
18932 if (!spec->loopback.amplist)
18933 spec->loopback.amplist = alc662_loopbacks;
18934#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018935
18936 return 0;
18937}
18938
Kailang Yang274693f2009-12-03 10:07:50 +010018939static int patch_alc888(struct hda_codec *codec)
18940{
18941 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18942 kfree(codec->chip_name);
18943 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018944 if (!codec->chip_name) {
18945 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018946 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018947 }
18948 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018949 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018950 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018951}
18952
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018953/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018954 * ALC680 support
18955 */
18956#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
18957#define alc680_modes alc260_modes
18958
18959static hda_nid_t alc680_dac_nids[3] = {
18960 /* Lout1, Lout2, hp */
18961 0x02, 0x03, 0x04
18962};
18963
18964static hda_nid_t alc680_adc_nids[3] = {
18965 /* ADC0-2 */
18966 /* DMIC, MIC, Line-in*/
18967 0x07, 0x08, 0x09
18968};
18969
18970static struct snd_kcontrol_new alc680_base_mixer[] = {
18971 /* output mixer control */
18972 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
18973 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18974 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
18975 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
18976 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
18977 { }
18978};
18979
18980static struct snd_kcontrol_new alc680_capture_mixer[] = {
18981 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
18982 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
18983 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
18984 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
18985 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
18986 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
18987 { } /* end */
18988};
18989
18990/*
18991 * generic initialization of ADC, input mixers and output mixers
18992 */
18993static struct hda_verb alc680_init_verbs[] = {
18994 /* Unmute DAC0-1 and set vol = 0 */
18995 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18996 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18997 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18998
18999 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19000 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19001 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
19002 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
19003 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
19004
19005 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19006 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19007 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19008 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19009 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19010 { }
19011};
19012
19013/* create input playback/capture controls for the given pin */
19014static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19015 const char *ctlname, int idx)
19016{
19017 hda_nid_t dac;
19018 int err;
19019
19020 switch (nid) {
19021 case 0x14:
19022 dac = 0x02;
19023 break;
19024 case 0x15:
19025 dac = 0x03;
19026 break;
19027 case 0x16:
19028 dac = 0x04;
19029 break;
19030 default:
19031 return 0;
19032 }
19033 if (spec->multiout.dac_nids[0] != dac &&
19034 spec->multiout.dac_nids[1] != dac) {
19035 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19036 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19037 HDA_OUTPUT));
19038 if (err < 0)
19039 return err;
19040
19041 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19042 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19043
19044 if (err < 0)
19045 return err;
19046 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19047 }
19048
19049 return 0;
19050}
19051
19052/* add playback controls from the parsed DAC table */
19053static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19054 const struct auto_pin_cfg *cfg)
19055{
19056 hda_nid_t nid;
19057 int err;
19058
19059 spec->multiout.dac_nids = spec->private_dac_nids;
19060
19061 nid = cfg->line_out_pins[0];
19062 if (nid) {
19063 const char *name;
19064 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19065 name = "Speaker";
19066 else
19067 name = "Front";
19068 err = alc680_new_analog_output(spec, nid, name, 0);
19069 if (err < 0)
19070 return err;
19071 }
19072
19073 nid = cfg->speaker_pins[0];
19074 if (nid) {
19075 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19076 if (err < 0)
19077 return err;
19078 }
19079 nid = cfg->hp_pins[0];
19080 if (nid) {
19081 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19082 if (err < 0)
19083 return err;
19084 }
19085
19086 return 0;
19087}
19088
19089static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19090 hda_nid_t nid, int pin_type)
19091{
19092 alc_set_pin_output(codec, nid, pin_type);
19093}
19094
19095static void alc680_auto_init_multi_out(struct hda_codec *codec)
19096{
19097 struct alc_spec *spec = codec->spec;
19098 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19099 if (nid) {
19100 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19101 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19102 }
19103}
19104
19105static void alc680_auto_init_hp_out(struct hda_codec *codec)
19106{
19107 struct alc_spec *spec = codec->spec;
19108 hda_nid_t pin;
19109
19110 pin = spec->autocfg.hp_pins[0];
19111 if (pin)
19112 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19113 pin = spec->autocfg.speaker_pins[0];
19114 if (pin)
19115 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19116}
19117
19118/* pcm configuration: identical with ALC880 */
19119#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19120#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19121#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19122#define alc680_pcm_digital_playback alc880_pcm_digital_playback
19123
19124static struct hda_input_mux alc680_capture_source = {
19125 .num_items = 1,
19126 .items = {
19127 { "Mic", 0x0 },
19128 },
19129};
19130
19131/*
19132 * BIOS auto configuration
19133 */
19134static int alc680_parse_auto_config(struct hda_codec *codec)
19135{
19136 struct alc_spec *spec = codec->spec;
19137 int err;
19138 static hda_nid_t alc680_ignore[] = { 0 };
19139
19140 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19141 alc680_ignore);
19142 if (err < 0)
19143 return err;
19144 if (!spec->autocfg.line_outs) {
19145 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19146 spec->multiout.max_channels = 2;
19147 spec->no_analog = 1;
19148 goto dig_only;
19149 }
19150 return 0; /* can't find valid BIOS pin config */
19151 }
19152 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19153 if (err < 0)
19154 return err;
19155
19156 spec->multiout.max_channels = 2;
19157
19158 dig_only:
19159 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019160 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019161 if (spec->kctls.list)
19162 add_mixer(spec, spec->kctls.list);
19163
19164 add_verb(spec, alc680_init_verbs);
19165 spec->num_mux_defs = 1;
19166 spec->input_mux = &alc680_capture_source;
19167
19168 err = alc_auto_add_mic_boost(codec);
19169 if (err < 0)
19170 return err;
19171
19172 return 1;
19173}
19174
19175#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19176
19177/* init callback for auto-configuration model -- overriding the default init */
19178static void alc680_auto_init(struct hda_codec *codec)
19179{
19180 struct alc_spec *spec = codec->spec;
19181 alc680_auto_init_multi_out(codec);
19182 alc680_auto_init_hp_out(codec);
19183 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019184 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019185 if (spec->unsol_event)
19186 alc_inithook(codec);
19187}
19188
19189/*
19190 * configuration and preset
19191 */
19192static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019193 [ALC680_BASE] = "base",
19194 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019195};
19196
19197static struct snd_pci_quirk alc680_cfg_tbl[] = {
19198 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19199 {}
19200};
19201
19202static struct alc_config_preset alc680_presets[] = {
19203 [ALC680_BASE] = {
19204 .mixers = { alc680_base_mixer },
19205 .cap_mixer = alc680_capture_mixer,
19206 .init_verbs = { alc680_init_verbs },
19207 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19208 .dac_nids = alc680_dac_nids,
19209 .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
19210 .adc_nids = alc680_adc_nids,
19211 .hp_nid = 0x04,
19212 .dig_out_nid = ALC680_DIGOUT_NID,
19213 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19214 .channel_mode = alc680_modes,
19215 .input_mux = &alc680_capture_source,
19216 },
19217};
19218
19219static int patch_alc680(struct hda_codec *codec)
19220{
19221 struct alc_spec *spec;
19222 int board_config;
19223 int err;
19224
19225 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19226 if (spec == NULL)
19227 return -ENOMEM;
19228
19229 codec->spec = spec;
19230
19231 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19232 alc680_models,
19233 alc680_cfg_tbl);
19234
19235 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19236 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19237 codec->chip_name);
19238 board_config = ALC680_AUTO;
19239 }
19240
19241 if (board_config == ALC680_AUTO) {
19242 /* automatic parse from the BIOS config */
19243 err = alc680_parse_auto_config(codec);
19244 if (err < 0) {
19245 alc_free(codec);
19246 return err;
19247 } else if (!err) {
19248 printk(KERN_INFO
19249 "hda_codec: Cannot set up configuration "
19250 "from BIOS. Using base mode...\n");
19251 board_config = ALC680_BASE;
19252 }
19253 }
19254
19255 if (board_config != ALC680_AUTO)
19256 setup_preset(codec, &alc680_presets[board_config]);
19257
19258 spec->stream_analog_playback = &alc680_pcm_analog_playback;
19259 spec->stream_analog_capture = &alc680_pcm_analog_capture;
19260 spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
19261 spec->stream_digital_playback = &alc680_pcm_digital_playback;
19262
19263 if (!spec->adc_nids) {
19264 spec->adc_nids = alc680_adc_nids;
19265 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19266 }
19267
19268 if (!spec->cap_mixer)
19269 set_capture_mixer(codec);
19270
19271 spec->vmaster_nid = 0x02;
19272
19273 codec->patch_ops = alc_patch_ops;
19274 if (board_config == ALC680_AUTO)
19275 spec->init_hook = alc680_auto_init;
19276
19277 return 0;
19278}
19279
19280/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019281 * patch entries
19282 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019283static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019284 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019285 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019286 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019287 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019288 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019289 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019290 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019291 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019292 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019293 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019294 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19295 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19296 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019297 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020019298 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019299 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19300 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019301 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019302 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019303 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019304 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019305 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019306 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019307 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019308 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019309 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019310 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019311 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019312 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019313 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019314 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020019315 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019316 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020019317 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019318 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019319 {} /* terminator */
19320};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019321
19322MODULE_ALIAS("snd-hda-codec-id:10ec*");
19323
19324MODULE_LICENSE("GPL");
19325MODULE_DESCRIPTION("Realtek HD-audio codec");
19326
19327static struct hda_codec_preset_list realtek_list = {
19328 .preset = snd_hda_preset_realtek,
19329 .owner = THIS_MODULE,
19330};
19331
19332static int __init patch_realtek_init(void)
19333{
19334 return snd_hda_add_codec_preset(&realtek_list);
19335}
19336
19337static void __exit patch_realtek_exit(void)
19338{
19339 snd_hda_delete_codec_preset(&realtek_list);
19340}
19341
19342module_init(patch_realtek_init)
19343module_exit(patch_realtek_exit)