blob: ce6c3a9c08c02a8245537ee5813f14db855fac7c [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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwaic8b6bf92005-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +02007072#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007073
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwaic8b6bf92005-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +02009432
Takashi Iwaicb53c622007-08-10 17:21:45 +02009433#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +02009504 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009505};
9506
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +02009630
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009631 {}
9632};
9633
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +02009659 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009660};
9661
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +020010748 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010749 hda_nid_t items[16];
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwaifdbc66262009-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 Iwaifdbc66262009-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 Iwaifdbc66262009-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 Iwaib08b1632010-07-30 14:08:25 +020013161 case 0x1a: /* ALC259/269 only */
13162 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013163 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013164 dac = 0x03;
13165 break;
13166 default:
13167 return 0;
13168 }
13169 if (spec->multiout.dac_nids[0] != dac &&
13170 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013171 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013172 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013173 HDA_OUTPUT));
13174 if (err < 0)
13175 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013176 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13177 }
13178
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013179 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013180 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013181 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013182 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013183 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013184 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013185 if (err < 0)
13186 return err;
13187 return 0;
13188}
13189
13190/* add playback controls from the parsed DAC table */
13191static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13192 const struct auto_pin_cfg *cfg)
13193{
13194 hda_nid_t nid;
13195 int err;
13196
Kailang Yanga361d842007-06-05 12:30:55 +020013197 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013198
13199 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013200 if (nid) {
13201 const char *name;
13202 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13203 name = "Speaker";
13204 else
13205 name = "Front";
13206 err = alc268_new_analog_output(spec, nid, name, 0);
13207 if (err < 0)
13208 return err;
13209 }
Kailang Yanga361d842007-06-05 12:30:55 +020013210
13211 nid = cfg->speaker_pins[0];
13212 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013213 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013214 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13215 if (err < 0)
13216 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013217 } else {
13218 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13219 if (err < 0)
13220 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013221 }
13222 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013223 if (nid) {
13224 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13225 if (err < 0)
13226 return err;
13227 }
Kailang Yanga361d842007-06-05 12:30:55 +020013228
13229 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13230 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013231 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013232 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013233 if (err < 0)
13234 return err;
13235 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013236 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013237}
13238
13239/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013240static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013241 const struct auto_pin_cfg *cfg)
13242{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013243 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013244}
13245
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013246static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13247 hda_nid_t nid, int pin_type)
13248{
13249 int idx;
13250
13251 alc_set_pin_output(codec, nid, pin_type);
13252 if (nid == 0x14 || nid == 0x16)
13253 idx = 0;
13254 else
13255 idx = 1;
13256 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13257}
13258
13259static void alc268_auto_init_multi_out(struct hda_codec *codec)
13260{
13261 struct alc_spec *spec = codec->spec;
13262 hda_nid_t nid = spec->autocfg.line_out_pins[0];
13263 if (nid) {
13264 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13265 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13266 }
13267}
13268
13269static void alc268_auto_init_hp_out(struct hda_codec *codec)
13270{
13271 struct alc_spec *spec = codec->spec;
13272 hda_nid_t pin;
13273
13274 pin = spec->autocfg.hp_pins[0];
13275 if (pin)
13276 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
13277 pin = spec->autocfg.speaker_pins[0];
13278 if (pin)
13279 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
13280}
13281
Kailang Yanga361d842007-06-05 12:30:55 +020013282static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13283{
13284 struct alc_spec *spec = codec->spec;
13285 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13286 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13287 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13288 unsigned int dac_vol1, dac_vol2;
13289
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013290 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013291 snd_hda_codec_write(codec, speaker_nid, 0,
13292 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013293 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013294 snd_hda_codec_write(codec, 0x0f, 0,
13295 AC_VERB_SET_AMP_GAIN_MUTE,
13296 AMP_IN_UNMUTE(1));
13297 snd_hda_codec_write(codec, 0x10, 0,
13298 AC_VERB_SET_AMP_GAIN_MUTE,
13299 AMP_IN_UNMUTE(1));
13300 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013301 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013302 snd_hda_codec_write(codec, 0x0f, 0,
13303 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13304 snd_hda_codec_write(codec, 0x10, 0,
13305 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13306 }
13307
13308 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013309 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013310 dac_vol2 = AMP_OUT_ZERO;
13311 else if (line_nid == 0x15)
13312 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013313 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013314 dac_vol2 = AMP_OUT_ZERO;
13315 else if (hp_nid == 0x15)
13316 dac_vol1 = AMP_OUT_ZERO;
13317 if (line_nid != 0x16 || hp_nid != 0x16 ||
13318 spec->autocfg.line_out_pins[1] != 0x16 ||
13319 spec->autocfg.line_out_pins[2] != 0x16)
13320 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13321
13322 snd_hda_codec_write(codec, 0x02, 0,
13323 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13324 snd_hda_codec_write(codec, 0x03, 0,
13325 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13326}
13327
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013328/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013329#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13330#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013331#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013332#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13333
13334/*
13335 * BIOS auto configuration
13336 */
13337static int alc268_parse_auto_config(struct hda_codec *codec)
13338{
13339 struct alc_spec *spec = codec->spec;
13340 int err;
13341 static hda_nid_t alc268_ignore[] = { 0 };
13342
13343 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13344 alc268_ignore);
13345 if (err < 0)
13346 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013347 if (!spec->autocfg.line_outs) {
13348 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13349 spec->multiout.max_channels = 2;
13350 spec->no_analog = 1;
13351 goto dig_only;
13352 }
Kailang Yanga361d842007-06-05 12:30:55 +020013353 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013354 }
Kailang Yanga361d842007-06-05 12:30:55 +020013355 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13356 if (err < 0)
13357 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013358 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013359 if (err < 0)
13360 return err;
13361
13362 spec->multiout.max_channels = 2;
13363
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013364 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013365 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013366 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013367 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013368 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013369
Takashi Iwai892981f2009-03-02 08:04:35 +010013370 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013371 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013372
Takashi Iwaid88897e2008-10-31 15:01:37 +010013373 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013374 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013375 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013376
Takashi Iwai776e1842007-08-29 15:07:11 +020013377 err = alc_auto_add_mic_boost(codec);
13378 if (err < 0)
13379 return err;
13380
Kailang Yang6227cdc2010-02-25 08:36:52 +010013381 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013382
Kailang Yanga361d842007-06-05 12:30:55 +020013383 return 1;
13384}
13385
Kailang Yanga361d842007-06-05 12:30:55 +020013386#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13387
13388/* init callback for auto-configuration model -- overriding the default init */
13389static void alc268_auto_init(struct hda_codec *codec)
13390{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013391 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013392 alc268_auto_init_multi_out(codec);
13393 alc268_auto_init_hp_out(codec);
13394 alc268_auto_init_mono_speaker_out(codec);
13395 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013396 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013397 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013398 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013399}
13400
13401/*
13402 * configuration and preset
13403 */
13404static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013405 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013406 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013407 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013408 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013409 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013410 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013411 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013412 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013413#ifdef CONFIG_SND_DEBUG
13414 [ALC268_TEST] = "test",
13415#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013416 [ALC268_AUTO] = "auto",
13417};
13418
13419static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013420 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013421 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013422 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013423 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013424 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013425 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13426 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013427 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013428 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13429 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013430 /* almost compatible with toshiba but with optional digital outs;
13431 * auto-probing seems working fine
13432 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013433 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013434 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013435 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013436 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013437 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013438 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013439 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013440 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020013441 {}
13442};
13443
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013444/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13445static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13446 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13447 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13448 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13449 ALC268_TOSHIBA),
13450 {}
13451};
13452
Kailang Yanga361d842007-06-05 12:30:55 +020013453static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013454 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013455 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13456 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013457 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13458 alc267_quanta_il1_verbs },
13459 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13460 .dac_nids = alc268_dac_nids,
13461 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13462 .adc_nids = alc268_adc_nids_alt,
13463 .hp_nid = 0x03,
13464 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13465 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013466 .unsol_event = alc_sku_unsol_event,
13467 .setup = alc267_quanta_il1_setup,
13468 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013469 },
Kailang Yanga361d842007-06-05 12:30:55 +020013470 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013471 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13472 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013473 .init_verbs = { alc268_base_init_verbs },
13474 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13475 .dac_nids = alc268_dac_nids,
13476 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13477 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013478 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013479 .hp_nid = 0x03,
13480 .dig_out_nid = ALC268_DIGOUT_NID,
13481 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13482 .channel_mode = alc268_modes,
13483 .input_mux = &alc268_capture_source,
13484 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013485 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013486 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013487 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013488 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13489 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013490 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13491 .dac_nids = alc268_dac_nids,
13492 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13493 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013494 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013495 .hp_nid = 0x03,
13496 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13497 .channel_mode = alc268_modes,
13498 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013499 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013500 .setup = alc268_toshiba_setup,
13501 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013502 },
13503 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013504 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013505 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013506 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13507 alc268_acer_verbs },
13508 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13509 .dac_nids = alc268_dac_nids,
13510 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13511 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013512 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013513 .hp_nid = 0x02,
13514 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13515 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013516 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013517 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013518 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013519 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013520 [ALC268_ACER_DMIC] = {
13521 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13522 alc268_beep_mixer },
13523 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13524 alc268_acer_verbs },
13525 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13526 .dac_nids = alc268_dac_nids,
13527 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13528 .adc_nids = alc268_adc_nids_alt,
13529 .capsrc_nids = alc268_capsrc_nids,
13530 .hp_nid = 0x02,
13531 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13532 .channel_mode = alc268_modes,
13533 .input_mux = &alc268_acer_dmic_capture_source,
13534 .unsol_event = alc268_acer_unsol_event,
13535 .init_hook = alc268_acer_init_hook,
13536 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013537 [ALC268_ACER_ASPIRE_ONE] = {
13538 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013539 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013540 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013541 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13542 alc268_acer_aspire_one_verbs },
13543 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13544 .dac_nids = alc268_dac_nids,
13545 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13546 .adc_nids = alc268_adc_nids_alt,
13547 .capsrc_nids = alc268_capsrc_nids,
13548 .hp_nid = 0x03,
13549 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13550 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013551 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013552 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013553 .init_hook = alc268_acer_lc_init_hook,
13554 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013555 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013556 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13557 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013558 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13559 alc268_dell_verbs },
13560 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13561 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013562 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13563 .adc_nids = alc268_adc_nids_alt,
13564 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013565 .hp_nid = 0x02,
13566 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13567 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013568 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013569 .setup = alc268_dell_setup,
13570 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013571 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013572 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013573 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13574 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013575 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13576 alc268_toshiba_verbs },
13577 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13578 .dac_nids = alc268_dac_nids,
13579 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13580 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013581 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013582 .hp_nid = 0x03,
13583 .dig_out_nid = ALC268_DIGOUT_NID,
13584 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13585 .channel_mode = alc268_modes,
13586 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013587 .setup = alc268_toshiba_setup,
13588 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013589 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013590#ifdef CONFIG_SND_DEBUG
13591 [ALC268_TEST] = {
13592 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13593 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13594 alc268_volume_init_verbs },
13595 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13596 .dac_nids = alc268_dac_nids,
13597 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13598 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013599 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013600 .hp_nid = 0x03,
13601 .dig_out_nid = ALC268_DIGOUT_NID,
13602 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13603 .channel_mode = alc268_modes,
13604 .input_mux = &alc268_capture_source,
13605 },
13606#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013607};
13608
13609static int patch_alc268(struct hda_codec *codec)
13610{
13611 struct alc_spec *spec;
13612 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013613 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013614
Julia Lawallef86f582009-12-19 08:18:03 +010013615 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013616 if (spec == NULL)
13617 return -ENOMEM;
13618
13619 codec->spec = spec;
13620
13621 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13622 alc268_models,
13623 alc268_cfg_tbl);
13624
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013625 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13626 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013627 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013628
Kailang Yanga361d842007-06-05 12:30:55 +020013629 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013630 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13631 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013632 board_config = ALC268_AUTO;
13633 }
13634
13635 if (board_config == ALC268_AUTO) {
13636 /* automatic parse from the BIOS config */
13637 err = alc268_parse_auto_config(codec);
13638 if (err < 0) {
13639 alc_free(codec);
13640 return err;
13641 } else if (!err) {
13642 printk(KERN_INFO
13643 "hda_codec: Cannot set up configuration "
13644 "from BIOS. Using base mode...\n");
13645 board_config = ALC268_3ST;
13646 }
13647 }
13648
13649 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013650 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013651
Kailang Yanga361d842007-06-05 12:30:55 +020013652 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13653 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013654 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013655
Kailang Yanga361d842007-06-05 12:30:55 +020013656 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13657
Takashi Iwai22971e32009-02-10 11:56:44 +010013658 has_beep = 0;
13659 for (i = 0; i < spec->num_mixers; i++) {
13660 if (spec->mixers[i] == alc268_beep_mixer) {
13661 has_beep = 1;
13662 break;
13663 }
13664 }
13665
13666 if (has_beep) {
13667 err = snd_hda_attach_beep_device(codec, 0x1);
13668 if (err < 0) {
13669 alc_free(codec);
13670 return err;
13671 }
13672 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13673 /* override the amp caps for beep generator */
13674 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013675 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13676 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13677 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13678 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013679 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013680
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013681 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013682 /* check whether NID 0x07 is valid */
13683 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013684 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013685
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013686 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013687 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013688 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013689 if (spec->auto_mic ||
13690 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013691 spec->adc_nids = alc268_adc_nids_alt;
13692 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013693 if (spec->auto_mic)
13694 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013695 if (spec->auto_mic || spec->input_mux->num_items == 1)
13696 add_mixer(spec, alc268_capture_nosrc_mixer);
13697 else
13698 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013699 } else {
13700 spec->adc_nids = alc268_adc_nids;
13701 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013702 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013703 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013704 /* set default input source */
13705 for (i = 0; i < spec->num_adc_nids; i++)
13706 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13707 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013708 i < spec->num_mux_defs ?
13709 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013710 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013711 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013712
13713 spec->vmaster_nid = 0x02;
13714
Kailang Yanga361d842007-06-05 12:30:55 +020013715 codec->patch_ops = alc_patch_ops;
13716 if (board_config == ALC268_AUTO)
13717 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013718
Kailang Yanga361d842007-06-05 12:30:55 +020013719 return 0;
13720}
13721
13722/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013723 * ALC269 channel source setting (2 channel)
13724 */
13725#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13726
13727#define alc269_dac_nids alc260_dac_nids
13728
13729static hda_nid_t alc269_adc_nids[1] = {
13730 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013731 0x08,
13732};
13733
Takashi Iwaie01bf502008-08-21 16:25:07 +020013734static hda_nid_t alc269_capsrc_nids[1] = {
13735 0x23,
13736};
13737
Kailang Yang84898e82010-02-04 14:16:14 +010013738static hda_nid_t alc269vb_adc_nids[1] = {
13739 /* ADC1 */
13740 0x09,
13741};
13742
13743static hda_nid_t alc269vb_capsrc_nids[1] = {
13744 0x22,
13745};
13746
Takashi Iwai66946352010-03-29 17:21:45 +020013747static hda_nid_t alc269_adc_candidates[] = {
13748 0x08, 0x09, 0x07,
13749};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013750
Kailang Yangf6a92242007-12-13 16:52:54 +010013751#define alc269_modes alc260_modes
13752#define alc269_capture_source alc880_lg_lw_capture_source
13753
13754static struct snd_kcontrol_new alc269_base_mixer[] = {
13755 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13756 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13757 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13758 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13759 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13760 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13761 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13762 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13763 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13764 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13765 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13766 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13767 { } /* end */
13768};
13769
Kailang Yang60db6b52008-08-26 13:13:00 +020013770static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13771 /* output mixer control */
13772 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13773 {
13774 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13775 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013776 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013777 .info = snd_hda_mixer_amp_switch_info,
13778 .get = snd_hda_mixer_amp_switch_get,
13779 .put = alc268_acer_master_sw_put,
13780 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13781 },
13782 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13783 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13784 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13785 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13786 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13787 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013788 { }
13789};
13790
Tony Vroon64154832008-11-06 15:08:49 +000013791static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13792 /* output mixer control */
13793 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13794 {
13795 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13796 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013797 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013798 .info = snd_hda_mixer_amp_switch_info,
13799 .get = snd_hda_mixer_amp_switch_get,
13800 .put = alc268_acer_master_sw_put,
13801 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13802 },
13803 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13804 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13805 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13806 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13807 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13808 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13809 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13810 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13811 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013812 { }
13813};
13814
Kailang Yang84898e82010-02-04 14:16:14 +010013815static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013816 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013817 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013818 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013819 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013820 { } /* end */
13821};
13822
Kailang Yang84898e82010-02-04 14:16:14 +010013823static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
13824 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13825 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13826 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13827 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13828 { } /* end */
13829};
13830
Kailang Yangf6a92242007-12-13 16:52:54 +010013831/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010013832static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
13833 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13834 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13835 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13836 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13837 { } /* end */
13838};
13839
13840static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013841 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13842 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013843 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13844 { } /* end */
13845};
13846
Kailang Yang84898e82010-02-04 14:16:14 +010013847static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
13848 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13849 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13850 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13851 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13852 { } /* end */
13853};
13854
13855static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
13856 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13857 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13858 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13859 { } /* end */
13860};
13861
Takashi Iwai26f5df22008-11-03 17:39:46 +010013862/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013863#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013864
Kailang Yang60db6b52008-08-26 13:13:00 +020013865static struct hda_verb alc269_quanta_fl1_verbs[] = {
13866 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13867 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13868 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13869 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13870 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13871 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13872 { }
13873};
13874
Tony Vroon64154832008-11-06 15:08:49 +000013875static struct hda_verb alc269_lifebook_verbs[] = {
13876 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13877 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13878 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13879 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13880 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13881 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13882 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13883 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13884 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13885 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13886 { }
13887};
13888
Kailang Yang60db6b52008-08-26 13:13:00 +020013889/* toggle speaker-output according to the hp-jack state */
13890static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13891{
13892 unsigned int present;
13893 unsigned char bits;
13894
Wu Fengguang864f92b2009-11-18 12:38:02 +080013895 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013896 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020013897 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013898 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013899 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013900 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013901
13902 snd_hda_codec_write(codec, 0x20, 0,
13903 AC_VERB_SET_COEF_INDEX, 0x0c);
13904 snd_hda_codec_write(codec, 0x20, 0,
13905 AC_VERB_SET_PROC_COEF, 0x680);
13906
13907 snd_hda_codec_write(codec, 0x20, 0,
13908 AC_VERB_SET_COEF_INDEX, 0x0c);
13909 snd_hda_codec_write(codec, 0x20, 0,
13910 AC_VERB_SET_PROC_COEF, 0x480);
13911}
13912
Tony Vroon64154832008-11-06 15:08:49 +000013913/* toggle speaker-output according to the hp-jacks state */
13914static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13915{
13916 unsigned int present;
13917 unsigned char bits;
13918
13919 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013920 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013921
13922 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013923 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013924
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013925 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000013926 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013927 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013928 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013929 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013930
13931 snd_hda_codec_write(codec, 0x20, 0,
13932 AC_VERB_SET_COEF_INDEX, 0x0c);
13933 snd_hda_codec_write(codec, 0x20, 0,
13934 AC_VERB_SET_PROC_COEF, 0x680);
13935
13936 snd_hda_codec_write(codec, 0x20, 0,
13937 AC_VERB_SET_COEF_INDEX, 0x0c);
13938 snd_hda_codec_write(codec, 0x20, 0,
13939 AC_VERB_SET_PROC_COEF, 0x480);
13940}
13941
Tony Vroon64154832008-11-06 15:08:49 +000013942static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13943{
13944 unsigned int present_laptop;
13945 unsigned int present_dock;
13946
Wu Fengguang864f92b2009-11-18 12:38:02 +080013947 present_laptop = snd_hda_jack_detect(codec, 0x18);
13948 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013949
13950 /* Laptop mic port overrides dock mic port, design decision */
13951 if (present_dock)
13952 snd_hda_codec_write(codec, 0x23, 0,
13953 AC_VERB_SET_CONNECT_SEL, 0x3);
13954 if (present_laptop)
13955 snd_hda_codec_write(codec, 0x23, 0,
13956 AC_VERB_SET_CONNECT_SEL, 0x0);
13957 if (!present_dock && !present_laptop)
13958 snd_hda_codec_write(codec, 0x23, 0,
13959 AC_VERB_SET_CONNECT_SEL, 0x1);
13960}
13961
Kailang Yang60db6b52008-08-26 13:13:00 +020013962static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13963 unsigned int res)
13964{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013965 switch (res >> 26) {
13966 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013967 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013968 break;
13969 case ALC880_MIC_EVENT:
13970 alc_mic_automute(codec);
13971 break;
13972 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013973}
13974
Tony Vroon64154832008-11-06 15:08:49 +000013975static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13976 unsigned int res)
13977{
13978 if ((res >> 26) == ALC880_HP_EVENT)
13979 alc269_lifebook_speaker_automute(codec);
13980 if ((res >> 26) == ALC880_MIC_EVENT)
13981 alc269_lifebook_mic_autoswitch(codec);
13982}
13983
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013984static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13985{
13986 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013987 spec->autocfg.hp_pins[0] = 0x15;
13988 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013989 spec->ext_mic.pin = 0x18;
13990 spec->ext_mic.mux_idx = 0;
13991 spec->int_mic.pin = 0x19;
13992 spec->int_mic.mux_idx = 1;
13993 spec->auto_mic = 1;
13994}
13995
Kailang Yang60db6b52008-08-26 13:13:00 +020013996static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13997{
13998 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013999 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014000}
14001
Tony Vroon64154832008-11-06 15:08:49 +000014002static void alc269_lifebook_init_hook(struct hda_codec *codec)
14003{
14004 alc269_lifebook_speaker_automute(codec);
14005 alc269_lifebook_mic_autoswitch(codec);
14006}
14007
Kailang Yang84898e82010-02-04 14:16:14 +010014008static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014009 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14010 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14011 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14012 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14013 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14014 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14015 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14016 {}
14017};
14018
Kailang Yang84898e82010-02-04 14:16:14 +010014019static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014020 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14021 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14022 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14023 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14024 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14025 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14026 {}
14027};
14028
Kailang Yang84898e82010-02-04 14:16:14 +010014029static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14030 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14031 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14032 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14033 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14034 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14035 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14036 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14037 {}
14038};
14039
14040static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14041 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14042 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14043 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14044 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14045 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14046 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14047 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14048 {}
14049};
14050
Kailang Yang60db6b52008-08-26 13:13:00 +020014051/* toggle speaker-output according to the hp-jack state */
14052static void alc269_speaker_automute(struct hda_codec *codec)
14053{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014054 struct alc_spec *spec = codec->spec;
14055 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014056 unsigned int present;
14057 unsigned char bits;
14058
Kailang Yangebb83ee2009-12-17 12:23:00 +010014059 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014060 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014061 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014062 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014063 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014064 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014065}
14066
Kailang Yang60db6b52008-08-26 13:13:00 +020014067/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014068static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014069 unsigned int res)
14070{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014071 switch (res >> 26) {
14072 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014073 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014074 break;
14075 case ALC880_MIC_EVENT:
14076 alc_mic_automute(codec);
14077 break;
14078 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014079}
14080
Kailang Yang226b1ec2010-04-09 11:01:20 +020014081static void alc269_laptop_amic_setup(struct hda_codec *codec)
14082{
14083 struct alc_spec *spec = codec->spec;
14084 spec->autocfg.hp_pins[0] = 0x15;
14085 spec->autocfg.speaker_pins[0] = 0x14;
14086 spec->ext_mic.pin = 0x18;
14087 spec->ext_mic.mux_idx = 0;
14088 spec->int_mic.pin = 0x19;
14089 spec->int_mic.mux_idx = 1;
14090 spec->auto_mic = 1;
14091}
14092
Kailang Yang84898e82010-02-04 14:16:14 +010014093static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014094{
14095 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014096 spec->autocfg.hp_pins[0] = 0x15;
14097 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014098 spec->ext_mic.pin = 0x18;
14099 spec->ext_mic.mux_idx = 0;
14100 spec->int_mic.pin = 0x12;
14101 spec->int_mic.mux_idx = 5;
14102 spec->auto_mic = 1;
14103}
14104
Kailang Yang226b1ec2010-04-09 11:01:20 +020014105static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014106{
14107 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014108 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014109 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014110 spec->ext_mic.pin = 0x18;
14111 spec->ext_mic.mux_idx = 0;
14112 spec->int_mic.pin = 0x19;
14113 spec->int_mic.mux_idx = 1;
14114 spec->auto_mic = 1;
14115}
14116
Kailang Yang226b1ec2010-04-09 11:01:20 +020014117static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14118{
14119 struct alc_spec *spec = codec->spec;
14120 spec->autocfg.hp_pins[0] = 0x21;
14121 spec->autocfg.speaker_pins[0] = 0x14;
14122 spec->ext_mic.pin = 0x18;
14123 spec->ext_mic.mux_idx = 0;
14124 spec->int_mic.pin = 0x12;
14125 spec->int_mic.mux_idx = 6;
14126 spec->auto_mic = 1;
14127}
14128
Kailang Yang84898e82010-02-04 14:16:14 +010014129static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014130{
14131 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014132 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014133}
14134
Kailang Yangf6a92242007-12-13 16:52:54 +010014135/*
14136 * generic initialization of ADC, input mixers and output mixers
14137 */
14138static struct hda_verb alc269_init_verbs[] = {
14139 /*
14140 * Unmute ADC0 and set the default input to mic-in
14141 */
Kailang Yang84898e82010-02-04 14:16:14 +010014142 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014143
14144 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014145 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014146 */
14147 /* set vol=0 to output mixers */
14148 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14149 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14150
14151 /* set up input amps for analog loopback */
14152 /* Amp Indices: DAC = 0, mixer = 1 */
14153 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14154 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14155 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14156 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14157 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14158 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14159
14160 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14161 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14162 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14163 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14164 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14165 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14166 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14167
14168 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14169 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014170
Kailang Yang84898e82010-02-04 14:16:14 +010014171 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014172 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14173 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014174 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014175
14176 /* set EAPD */
14177 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014178 { }
14179};
14180
14181static struct hda_verb alc269vb_init_verbs[] = {
14182 /*
14183 * Unmute ADC0 and set the default input to mic-in
14184 */
14185 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14186
14187 /*
14188 * Set up output mixers (0x02 - 0x03)
14189 */
14190 /* set vol=0 to output mixers */
14191 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14192 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14193
14194 /* set up input amps for analog loopback */
14195 /* Amp Indices: DAC = 0, mixer = 1 */
14196 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14197 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14198 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14199 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14200 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14201 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14202
14203 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14204 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14205 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14206 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14207 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14208 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14209 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14210
14211 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14212 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14213
14214 /* FIXME: use Mux-type input source selection */
14215 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14216 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14217 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14218
14219 /* set EAPD */
14220 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014221 { }
14222};
14223
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014224#define alc269_auto_create_multi_out_ctls \
14225 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014226#define alc269_auto_create_input_ctls \
14227 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014228
14229#ifdef CONFIG_SND_HDA_POWER_SAVE
14230#define alc269_loopbacks alc880_loopbacks
14231#endif
14232
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014233/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014234#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14235#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14236#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14237#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14238
Takashi Iwaif03d3112009-03-05 14:18:16 +010014239static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14240 .substreams = 1,
14241 .channels_min = 2,
14242 .channels_max = 8,
14243 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14244 /* NID is set in alc_build_pcms */
14245 .ops = {
14246 .open = alc880_playback_pcm_open,
14247 .prepare = alc880_playback_pcm_prepare,
14248 .cleanup = alc880_playback_pcm_cleanup
14249 },
14250};
14251
14252static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14253 .substreams = 1,
14254 .channels_min = 2,
14255 .channels_max = 2,
14256 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14257 /* NID is set in alc_build_pcms */
14258};
14259
Takashi Iwaiad358792010-03-30 18:00:59 +020014260#ifdef CONFIG_SND_HDA_POWER_SAVE
14261static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14262{
14263 switch (codec->subsystem_id) {
14264 case 0x103c1586:
14265 return 1;
14266 }
14267 return 0;
14268}
14269
14270static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14271{
14272 /* update mute-LED according to the speaker mute state */
14273 if (nid == 0x01 || nid == 0x14) {
14274 int pinval;
14275 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14276 HDA_AMP_MUTE)
14277 pinval = 0x24;
14278 else
14279 pinval = 0x20;
14280 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014281 snd_hda_codec_update_cache(codec, 0x19, 0,
14282 AC_VERB_SET_PIN_WIDGET_CONTROL,
14283 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014284 }
14285 return alc_check_power_status(codec, nid);
14286}
14287#endif /* CONFIG_SND_HDA_POWER_SAVE */
14288
Takashi Iwai840b64c2010-07-13 22:49:01 +020014289static int alc275_setup_dual_adc(struct hda_codec *codec)
14290{
14291 struct alc_spec *spec = codec->spec;
14292
14293 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14294 return 0;
14295 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14296 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14297 if (spec->ext_mic.pin <= 0x12) {
14298 spec->private_adc_nids[0] = 0x08;
14299 spec->private_adc_nids[1] = 0x11;
14300 spec->private_capsrc_nids[0] = 0x23;
14301 spec->private_capsrc_nids[1] = 0x22;
14302 } else {
14303 spec->private_adc_nids[0] = 0x11;
14304 spec->private_adc_nids[1] = 0x08;
14305 spec->private_capsrc_nids[0] = 0x22;
14306 spec->private_capsrc_nids[1] = 0x23;
14307 }
14308 spec->adc_nids = spec->private_adc_nids;
14309 spec->capsrc_nids = spec->private_capsrc_nids;
14310 spec->num_adc_nids = 2;
14311 spec->dual_adc_switch = 1;
14312 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14313 spec->adc_nids[0], spec->adc_nids[1]);
14314 return 1;
14315 }
14316 return 0;
14317}
14318
Kailang Yangf6a92242007-12-13 16:52:54 +010014319/*
14320 * BIOS auto configuration
14321 */
14322static int alc269_parse_auto_config(struct hda_codec *codec)
14323{
14324 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014325 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014326 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14327
14328 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14329 alc269_ignore);
14330 if (err < 0)
14331 return err;
14332
14333 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14334 if (err < 0)
14335 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014336 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010014337 if (err < 0)
14338 return err;
14339
14340 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14341
Takashi Iwai757899a2010-07-30 10:48:14 +020014342 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014343
Takashi Iwai603c4012008-07-30 15:01:44 +020014344 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014345 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014346
Kailang Yang84898e82010-02-04 14:16:14 +010014347 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
14348 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014349 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014350 } else {
14351 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014352 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014353 }
14354
Kailang Yangf6a92242007-12-13 16:52:54 +010014355 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014356 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014357
14358 if (!alc275_setup_dual_adc(codec))
14359 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14360 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014361
Takashi Iwaie01bf502008-08-21 16:25:07 +020014362 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014363 if (!spec->dual_adc_switch)
14364 snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
Takashi Iwaie01bf502008-08-21 16:25:07 +020014365 0, AC_VERB_SET_CONNECT_SEL,
14366 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014367
14368 err = alc_auto_add_mic_boost(codec);
14369 if (err < 0)
14370 return err;
14371
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014372 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014373 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014374
Kailang Yangf6a92242007-12-13 16:52:54 +010014375 return 1;
14376}
14377
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014378#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14379#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014380#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14381
14382
14383/* init callback for auto-configuration model -- overriding the default init */
14384static void alc269_auto_init(struct hda_codec *codec)
14385{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014386 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014387 alc269_auto_init_multi_out(codec);
14388 alc269_auto_init_hp_out(codec);
14389 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014390 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014391 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014392 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014393}
14394
Takashi Iwaiff818c22010-04-12 08:59:25 +020014395enum {
14396 ALC269_FIXUP_SONY_VAIO,
14397};
14398
Tobias Klauserfbc25662010-05-20 10:40:55 +020014399static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
Takashi Iwaiff818c22010-04-12 08:59:25 +020014400 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14401 {}
14402};
14403
14404static const struct alc_fixup alc269_fixups[] = {
14405 [ALC269_FIXUP_SONY_VAIO] = {
14406 .verbs = alc269_sony_vaio_fixup_verbs
14407 },
14408};
14409
14410static struct snd_pci_quirk alc269_fixup_tbl[] = {
14411 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
14412 {}
14413};
14414
14415
Kailang Yangf6a92242007-12-13 16:52:54 +010014416/*
14417 * configuration and preset
14418 */
14419static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014420 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014421 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014422 [ALC269_AMIC] = "laptop-amic",
14423 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014424 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014425 [ALC269_LIFEBOOK] = "lifebook",
14426 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014427};
14428
14429static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014430 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020014431 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014432 ALC269_AMIC),
14433 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14434 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14435 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14436 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14437 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14438 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14439 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14440 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14441 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14442 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14443 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14444 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14445 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14446 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14447 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14448 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14449 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14450 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14451 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14452 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14453 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14454 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14455 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14456 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14457 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14458 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14459 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14460 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14461 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14462 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14463 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14464 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14465 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14466 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14467 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14468 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014469 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014470 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014471 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014472 ALC269_DMIC),
14473 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14474 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014475 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014476 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014477 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14478 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14479 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14480 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14481 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14482 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014483 {}
14484};
14485
14486static struct alc_config_preset alc269_presets[] = {
14487 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014488 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014489 .init_verbs = { alc269_init_verbs },
14490 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14491 .dac_nids = alc269_dac_nids,
14492 .hp_nid = 0x03,
14493 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14494 .channel_mode = alc269_modes,
14495 .input_mux = &alc269_capture_source,
14496 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014497 [ALC269_QUANTA_FL1] = {
14498 .mixers = { alc269_quanta_fl1_mixer },
14499 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14500 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14501 .dac_nids = alc269_dac_nids,
14502 .hp_nid = 0x03,
14503 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14504 .channel_mode = alc269_modes,
14505 .input_mux = &alc269_capture_source,
14506 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014507 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014508 .init_hook = alc269_quanta_fl1_init_hook,
14509 },
Kailang Yang84898e82010-02-04 14:16:14 +010014510 [ALC269_AMIC] = {
14511 .mixers = { alc269_laptop_mixer },
14512 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014513 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014514 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014515 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14516 .dac_nids = alc269_dac_nids,
14517 .hp_nid = 0x03,
14518 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14519 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014520 .unsol_event = alc269_laptop_unsol_event,
14521 .setup = alc269_laptop_amic_setup,
14522 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014523 },
Kailang Yang84898e82010-02-04 14:16:14 +010014524 [ALC269_DMIC] = {
14525 .mixers = { alc269_laptop_mixer },
14526 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014527 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014528 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014529 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14530 .dac_nids = alc269_dac_nids,
14531 .hp_nid = 0x03,
14532 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14533 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014534 .unsol_event = alc269_laptop_unsol_event,
14535 .setup = alc269_laptop_dmic_setup,
14536 .init_hook = alc269_laptop_inithook,
14537 },
14538 [ALC269VB_AMIC] = {
14539 .mixers = { alc269vb_laptop_mixer },
14540 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14541 .init_verbs = { alc269vb_init_verbs,
14542 alc269vb_laptop_amic_init_verbs },
14543 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14544 .dac_nids = alc269_dac_nids,
14545 .hp_nid = 0x03,
14546 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14547 .channel_mode = alc269_modes,
14548 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014549 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014550 .init_hook = alc269_laptop_inithook,
14551 },
14552 [ALC269VB_DMIC] = {
14553 .mixers = { alc269vb_laptop_mixer },
14554 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14555 .init_verbs = { alc269vb_init_verbs,
14556 alc269vb_laptop_dmic_init_verbs },
14557 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14558 .dac_nids = alc269_dac_nids,
14559 .hp_nid = 0x03,
14560 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14561 .channel_mode = alc269_modes,
14562 .unsol_event = alc269_laptop_unsol_event,
14563 .setup = alc269vb_laptop_dmic_setup,
14564 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014565 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014566 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014567 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014568 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014569 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014570 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014571 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14572 .dac_nids = alc269_dac_nids,
14573 .hp_nid = 0x03,
14574 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14575 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014576 .unsol_event = alc269_laptop_unsol_event,
14577 .setup = alc269_laptop_dmic_setup,
14578 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014579 },
Tony Vroon64154832008-11-06 15:08:49 +000014580 [ALC269_LIFEBOOK] = {
14581 .mixers = { alc269_lifebook_mixer },
14582 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14583 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14584 .dac_nids = alc269_dac_nids,
14585 .hp_nid = 0x03,
14586 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14587 .channel_mode = alc269_modes,
14588 .input_mux = &alc269_capture_source,
14589 .unsol_event = alc269_lifebook_unsol_event,
14590 .init_hook = alc269_lifebook_init_hook,
14591 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014592};
14593
14594static int patch_alc269(struct hda_codec *codec)
14595{
14596 struct alc_spec *spec;
14597 int board_config;
14598 int err;
Kailang Yang84898e82010-02-04 14:16:14 +010014599 int is_alc269vb = 0;
Kailang Yangf6a92242007-12-13 16:52:54 +010014600
14601 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14602 if (spec == NULL)
14603 return -ENOMEM;
14604
14605 codec->spec = spec;
14606
Kailang Yangda00c242010-03-19 11:23:45 +010014607 alc_auto_parse_customize_define(codec);
14608
Kailang Yang274693f2009-12-03 10:07:50 +010014609 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014610 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14611 spec->cdefine.platform_type == 1)
14612 alc_codec_rename(codec, "ALC271X");
14613 else
14614 alc_codec_rename(codec, "ALC259");
Kailang Yang84898e82010-02-04 14:16:14 +010014615 is_alc269vb = 1;
Kailang Yangc027ddc2010-03-19 11:33:06 +010014616 } else
14617 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010014618
Kailang Yangf6a92242007-12-13 16:52:54 +010014619 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14620 alc269_models,
14621 alc269_cfg_tbl);
14622
14623 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014624 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14625 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014626 board_config = ALC269_AUTO;
14627 }
14628
Takashi Iwaiff818c22010-04-12 08:59:25 +020014629 if (board_config == ALC269_AUTO)
14630 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
14631
Kailang Yangf6a92242007-12-13 16:52:54 +010014632 if (board_config == ALC269_AUTO) {
14633 /* automatic parse from the BIOS config */
14634 err = alc269_parse_auto_config(codec);
14635 if (err < 0) {
14636 alc_free(codec);
14637 return err;
14638 } else if (!err) {
14639 printk(KERN_INFO
14640 "hda_codec: Cannot set up configuration "
14641 "from BIOS. Using base mode...\n");
14642 board_config = ALC269_BASIC;
14643 }
14644 }
14645
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014646 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014647 err = snd_hda_attach_beep_device(codec, 0x1);
14648 if (err < 0) {
14649 alc_free(codec);
14650 return err;
14651 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014652 }
14653
Kailang Yangf6a92242007-12-13 16:52:54 +010014654 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014655 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014656
Kailang Yang84898e82010-02-04 14:16:14 +010014657 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014658 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14659 * fix the sample rate of analog I/O to 44.1kHz
14660 */
14661 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14662 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020014663 } else if (spec->dual_adc_switch) {
14664 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14665 /* switch ADC dynamically */
14666 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014667 } else {
14668 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14669 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14670 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014671 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14672 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14673
Takashi Iwai66946352010-03-29 17:21:45 +020014674 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
14675 if (!is_alc269vb) {
14676 spec->adc_nids = alc269_adc_nids;
14677 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14678 spec->capsrc_nids = alc269_capsrc_nids;
14679 } else {
14680 spec->adc_nids = alc269vb_adc_nids;
14681 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14682 spec->capsrc_nids = alc269vb_capsrc_nids;
14683 }
Kailang Yang84898e82010-02-04 14:16:14 +010014684 }
14685
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014686 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014687 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014688 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014689 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014690
Takashi Iwaiff818c22010-04-12 08:59:25 +020014691 if (board_config == ALC269_AUTO)
14692 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
14693
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014694 spec->vmaster_nid = 0x02;
14695
Kailang Yangf6a92242007-12-13 16:52:54 +010014696 codec->patch_ops = alc_patch_ops;
14697 if (board_config == ALC269_AUTO)
14698 spec->init_hook = alc269_auto_init;
14699#ifdef CONFIG_SND_HDA_POWER_SAVE
14700 if (!spec->loopback.amplist)
14701 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014702 if (alc269_mic2_for_mute_led(codec))
14703 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014704#endif
14705
14706 return 0;
14707}
14708
14709/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014710 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14711 */
14712
14713/*
14714 * set the path ways for 2 channel output
14715 * need to set the codec line out and mic 1 pin widgets to inputs
14716 */
14717static struct hda_verb alc861_threestack_ch2_init[] = {
14718 /* set pin widget 1Ah (line in) for input */
14719 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014720 /* set pin widget 18h (mic1/2) for input, for mic also enable
14721 * the vref
14722 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014723 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14724
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014725 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14726#if 0
14727 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14728 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14729#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014730 { } /* end */
14731};
14732/*
14733 * 6ch mode
14734 * need to set the codec line out and mic 1 pin widgets to outputs
14735 */
14736static struct hda_verb alc861_threestack_ch6_init[] = {
14737 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14738 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14739 /* set pin widget 18h (mic1) for output (CLFE)*/
14740 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14741
14742 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014743 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014744
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014745 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14746#if 0
14747 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14748 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14749#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014750 { } /* end */
14751};
14752
14753static struct hda_channel_mode alc861_threestack_modes[2] = {
14754 { 2, alc861_threestack_ch2_init },
14755 { 6, alc861_threestack_ch6_init },
14756};
Takashi Iwai22309c32006-08-09 16:57:28 +020014757/* Set mic1 as input and unmute the mixer */
14758static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
14759 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14760 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14761 { } /* end */
14762};
14763/* Set mic1 as output and mute mixer */
14764static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
14765 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14766 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14767 { } /* end */
14768};
14769
14770static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
14771 { 2, alc861_uniwill_m31_ch2_init },
14772 { 4, alc861_uniwill_m31_ch4_init },
14773};
Kailang Yangdf694da2005-12-05 19:42:22 +010014774
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014775/* Set mic1 and line-in as input and unmute the mixer */
14776static struct hda_verb alc861_asus_ch2_init[] = {
14777 /* set pin widget 1Ah (line in) for input */
14778 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014779 /* set pin widget 18h (mic1/2) for input, for mic also enable
14780 * the vref
14781 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014782 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14783
14784 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14785#if 0
14786 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14787 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14788#endif
14789 { } /* end */
14790};
14791/* Set mic1 nad line-in as output and mute mixer */
14792static struct hda_verb alc861_asus_ch6_init[] = {
14793 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14794 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14795 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14796 /* set pin widget 18h (mic1) for output (CLFE)*/
14797 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14798 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14799 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14800 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14801
14802 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14803#if 0
14804 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14805 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14806#endif
14807 { } /* end */
14808};
14809
14810static struct hda_channel_mode alc861_asus_modes[2] = {
14811 { 2, alc861_asus_ch2_init },
14812 { 6, alc861_asus_ch6_init },
14813};
14814
Kailang Yangdf694da2005-12-05 19:42:22 +010014815/* patch-ALC861 */
14816
14817static struct snd_kcontrol_new alc861_base_mixer[] = {
14818 /* output mixer control */
14819 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14820 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14821 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14822 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14823 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14824
14825 /*Input mixer control */
14826 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14827 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14828 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14829 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14830 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14831 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14832 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14833 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14834 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14835 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014836
Kailang Yangdf694da2005-12-05 19:42:22 +010014837 { } /* end */
14838};
14839
14840static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14841 /* output mixer control */
14842 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14843 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14844 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14845 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14846 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14847
14848 /* Input mixer control */
14849 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14850 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14851 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14852 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14853 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14854 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14855 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14856 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14857 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14858 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014859
Kailang Yangdf694da2005-12-05 19:42:22 +010014860 {
14861 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14862 .name = "Channel Mode",
14863 .info = alc_ch_mode_info,
14864 .get = alc_ch_mode_get,
14865 .put = alc_ch_mode_put,
14866 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14867 },
14868 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014869};
14870
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014871static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014872 /* output mixer control */
14873 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14874 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14875 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014876
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014877 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014878};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014879
Takashi Iwai22309c32006-08-09 16:57:28 +020014880static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14881 /* output mixer control */
14882 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14883 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14884 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14885 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14886 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14887
14888 /* Input mixer control */
14889 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14890 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14891 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14892 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14893 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14894 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14895 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14896 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14897 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14898 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014899
Takashi Iwai22309c32006-08-09 16:57:28 +020014900 {
14901 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14902 .name = "Channel Mode",
14903 .info = alc_ch_mode_info,
14904 .get = alc_ch_mode_get,
14905 .put = alc_ch_mode_put,
14906 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14907 },
14908 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014909};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014910
14911static struct snd_kcontrol_new alc861_asus_mixer[] = {
14912 /* output mixer control */
14913 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14914 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14915 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14916 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14917 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14918
14919 /* Input mixer control */
14920 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14921 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14922 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14923 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14924 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14925 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14926 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14927 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14928 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014929 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14930
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014931 {
14932 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14933 .name = "Channel Mode",
14934 .info = alc_ch_mode_info,
14935 .get = alc_ch_mode_get,
14936 .put = alc_ch_mode_put,
14937 .private_value = ARRAY_SIZE(alc861_asus_modes),
14938 },
14939 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014940};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014941
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014942/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014943static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014944 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14945 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014946 { }
14947};
14948
Kailang Yangdf694da2005-12-05 19:42:22 +010014949/*
14950 * generic initialization of ADC, input mixers and output mixers
14951 */
14952static struct hda_verb alc861_base_init_verbs[] = {
14953 /*
14954 * Unmute ADC0 and set the default input to mic-in
14955 */
14956 /* port-A for surround (rear panel) */
14957 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14958 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14959 /* port-B for mic-in (rear panel) with vref */
14960 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14961 /* port-C for line-in (rear panel) */
14962 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14963 /* port-D for Front */
14964 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14965 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14966 /* port-E for HP out (front panel) */
14967 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14968 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014969 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014970 /* port-F for mic-in (front panel) with vref */
14971 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14972 /* port-G for CLFE (rear panel) */
14973 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14974 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14975 /* port-H for side (rear panel) */
14976 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14977 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14978 /* CD-in */
14979 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14980 /* route front mic to ADC1*/
14981 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14982 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014983
Kailang Yangdf694da2005-12-05 19:42:22 +010014984 /* Unmute DAC0~3 & spdif out*/
14985 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14986 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14987 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14988 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14989 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014990
Kailang Yangdf694da2005-12-05 19:42:22 +010014991 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14992 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14993 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14994 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14995 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014996
Kailang Yangdf694da2005-12-05 19:42:22 +010014997 /* Unmute Stereo Mixer 15 */
14998 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14999 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15000 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015001 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015002
15003 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15004 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15005 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15006 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15007 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15008 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15009 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15010 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015011 /* hp used DAC 3 (Front) */
15012 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015013 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15014
15015 { }
15016};
15017
15018static struct hda_verb alc861_threestack_init_verbs[] = {
15019 /*
15020 * Unmute ADC0 and set the default input to mic-in
15021 */
15022 /* port-A for surround (rear panel) */
15023 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15024 /* port-B for mic-in (rear panel) with vref */
15025 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15026 /* port-C for line-in (rear panel) */
15027 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15028 /* port-D for Front */
15029 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15030 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15031 /* port-E for HP out (front panel) */
15032 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15033 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015034 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015035 /* port-F for mic-in (front panel) with vref */
15036 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15037 /* port-G for CLFE (rear panel) */
15038 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15039 /* port-H for side (rear panel) */
15040 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15041 /* CD-in */
15042 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15043 /* route front mic to ADC1*/
15044 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15045 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15046 /* Unmute DAC0~3 & spdif out*/
15047 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15048 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15049 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15050 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15051 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015052
Kailang Yangdf694da2005-12-05 19:42:22 +010015053 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15054 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15055 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15056 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15057 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015058
Kailang Yangdf694da2005-12-05 19:42:22 +010015059 /* Unmute Stereo Mixer 15 */
15060 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15061 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15062 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015063 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015064
15065 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15066 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15067 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15068 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15069 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15070 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15071 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15072 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015073 /* hp used DAC 3 (Front) */
15074 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015075 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15076 { }
15077};
Takashi Iwai22309c32006-08-09 16:57:28 +020015078
15079static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15080 /*
15081 * Unmute ADC0 and set the default input to mic-in
15082 */
15083 /* port-A for surround (rear panel) */
15084 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15085 /* port-B for mic-in (rear panel) with vref */
15086 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15087 /* port-C for line-in (rear panel) */
15088 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15089 /* port-D for Front */
15090 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15091 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15092 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015093 /* this has to be set to VREF80 */
15094 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015095 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015096 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015097 /* port-F for mic-in (front panel) with vref */
15098 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15099 /* port-G for CLFE (rear panel) */
15100 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15101 /* port-H for side (rear panel) */
15102 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15103 /* CD-in */
15104 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15105 /* route front mic to ADC1*/
15106 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15107 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15108 /* Unmute DAC0~3 & spdif out*/
15109 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15110 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15111 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15112 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15113 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015114
Takashi Iwai22309c32006-08-09 16:57:28 +020015115 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15116 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15117 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15118 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15119 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015120
Takashi Iwai22309c32006-08-09 16:57:28 +020015121 /* Unmute Stereo Mixer 15 */
15122 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15123 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15124 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015125 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015126
15127 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15128 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15129 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15130 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15131 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15132 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15133 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15134 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015135 /* hp used DAC 3 (Front) */
15136 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015137 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15138 { }
15139};
15140
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015141static struct hda_verb alc861_asus_init_verbs[] = {
15142 /*
15143 * Unmute ADC0 and set the default input to mic-in
15144 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015145 /* port-A for surround (rear panel)
15146 * according to codec#0 this is the HP jack
15147 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015148 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15149 /* route front PCM to HP */
15150 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15151 /* port-B for mic-in (rear panel) with vref */
15152 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15153 /* port-C for line-in (rear panel) */
15154 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15155 /* port-D for Front */
15156 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15157 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15158 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015159 /* this has to be set to VREF80 */
15160 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015161 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015162 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015163 /* port-F for mic-in (front panel) with vref */
15164 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15165 /* port-G for CLFE (rear panel) */
15166 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15167 /* port-H for side (rear panel) */
15168 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15169 /* CD-in */
15170 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15171 /* route front mic to ADC1*/
15172 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15173 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15174 /* Unmute DAC0~3 & spdif out*/
15175 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15176 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15177 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15178 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15179 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15180 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15181 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15182 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15183 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15184 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015185
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015186 /* Unmute Stereo Mixer 15 */
15187 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15188 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015190 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015191
15192 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15193 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15194 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15195 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15196 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15197 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15198 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015200 /* hp used DAC 3 (Front) */
15201 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015202 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15203 { }
15204};
15205
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015206/* additional init verbs for ASUS laptops */
15207static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15208 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15209 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15210 { }
15211};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015212
Kailang Yangdf694da2005-12-05 19:42:22 +010015213/*
15214 * generic initialization of ADC, input mixers and output mixers
15215 */
15216static struct hda_verb alc861_auto_init_verbs[] = {
15217 /*
15218 * Unmute ADC0 and set the default input to mic-in
15219 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015220 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015221 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015222
Kailang Yangdf694da2005-12-05 19:42:22 +010015223 /* Unmute DAC0~3 & spdif out*/
15224 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15225 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15226 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15227 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15228 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015229
Kailang Yangdf694da2005-12-05 19:42:22 +010015230 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15231 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15232 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15233 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15234 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015235
Kailang Yangdf694da2005-12-05 19:42:22 +010015236 /* Unmute Stereo Mixer 15 */
15237 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15238 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15239 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15240 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15241
Takashi Iwai1c209302009-07-22 15:17:45 +020015242 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15243 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15244 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15245 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15246 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15247 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15248 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15249 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015250
15251 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15252 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015253 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15254 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015255 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15256 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015257 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15258 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015259
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015260 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015261
15262 { }
15263};
15264
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015265static struct hda_verb alc861_toshiba_init_verbs[] = {
15266 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015267
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015268 { }
15269};
15270
15271/* toggle speaker-output according to the hp-jack state */
15272static void alc861_toshiba_automute(struct hda_codec *codec)
15273{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015274 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015275
Takashi Iwai47fd8302007-08-10 17:11:07 +020015276 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15277 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15278 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15279 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015280}
15281
15282static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15283 unsigned int res)
15284{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015285 if ((res >> 26) == ALC880_HP_EVENT)
15286 alc861_toshiba_automute(codec);
15287}
15288
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015289/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015290#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15291#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15292#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15293#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15294
15295
15296#define ALC861_DIGOUT_NID 0x07
15297
15298static struct hda_channel_mode alc861_8ch_modes[1] = {
15299 { 8, NULL }
15300};
15301
15302static hda_nid_t alc861_dac_nids[4] = {
15303 /* front, surround, clfe, side */
15304 0x03, 0x06, 0x05, 0x04
15305};
15306
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015307static hda_nid_t alc660_dac_nids[3] = {
15308 /* front, clfe, surround */
15309 0x03, 0x05, 0x06
15310};
15311
Kailang Yangdf694da2005-12-05 19:42:22 +010015312static hda_nid_t alc861_adc_nids[1] = {
15313 /* ADC0-2 */
15314 0x08,
15315};
15316
15317static struct hda_input_mux alc861_capture_source = {
15318 .num_items = 5,
15319 .items = {
15320 { "Mic", 0x0 },
15321 { "Front Mic", 0x3 },
15322 { "Line", 0x1 },
15323 { "CD", 0x4 },
15324 { "Mixer", 0x5 },
15325 },
15326};
15327
Takashi Iwai1c209302009-07-22 15:17:45 +020015328static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15329{
15330 struct alc_spec *spec = codec->spec;
15331 hda_nid_t mix, srcs[5];
15332 int i, j, num;
15333
15334 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15335 return 0;
15336 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15337 if (num < 0)
15338 return 0;
15339 for (i = 0; i < num; i++) {
15340 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015341 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015342 if (type != AC_WID_AUD_OUT)
15343 continue;
15344 for (j = 0; j < spec->multiout.num_dacs; j++)
15345 if (spec->multiout.dac_nids[j] == srcs[i])
15346 break;
15347 if (j >= spec->multiout.num_dacs)
15348 return srcs[i];
15349 }
15350 return 0;
15351}
15352
Kailang Yangdf694da2005-12-05 19:42:22 +010015353/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015354static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015355 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015356{
Takashi Iwai1c209302009-07-22 15:17:45 +020015357 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015358 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015359 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015360
15361 spec->multiout.dac_nids = spec->private_dac_nids;
15362 for (i = 0; i < cfg->line_outs; i++) {
15363 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015364 dac = alc861_look_for_dac(codec, nid);
15365 if (!dac)
15366 continue;
15367 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015368 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015369 return 0;
15370}
15371
Takashi Iwai1c209302009-07-22 15:17:45 +020015372static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15373 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015374{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015375 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015376 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15377}
15378
15379/* add playback controls from the parsed DAC table */
15380static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15381 const struct auto_pin_cfg *cfg)
15382{
15383 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015384 static const char *chname[4] = {
15385 "Front", "Surround", NULL /*CLFE*/, "Side"
15386 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015387 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015388 int i, err;
15389
15390 if (cfg->line_outs == 1) {
15391 const char *pfx = NULL;
15392 if (!cfg->hp_outs)
15393 pfx = "Master";
15394 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15395 pfx = "Speaker";
15396 if (pfx) {
15397 nid = spec->multiout.dac_nids[0];
15398 return alc861_create_out_sw(codec, pfx, nid, 3);
15399 }
15400 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015401
15402 for (i = 0; i < cfg->line_outs; i++) {
15403 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015404 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015405 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015406 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015407 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015408 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015409 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015410 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015411 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015412 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015413 return err;
15414 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015415 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015416 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015417 return err;
15418 }
15419 }
15420 return 0;
15421}
15422
Takashi Iwai1c209302009-07-22 15:17:45 +020015423static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015424{
Takashi Iwai1c209302009-07-22 15:17:45 +020015425 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015426 int err;
15427 hda_nid_t nid;
15428
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015429 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015430 return 0;
15431
15432 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015433 nid = alc861_look_for_dac(codec, pin);
15434 if (nid) {
15435 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15436 if (err < 0)
15437 return err;
15438 spec->multiout.hp_nid = nid;
15439 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015440 }
15441 return 0;
15442}
15443
15444/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015445static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015446 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015447{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015448 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015449}
15450
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015451static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15452 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015453 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015454{
Takashi Iwai1c209302009-07-22 15:17:45 +020015455 hda_nid_t mix, srcs[5];
15456 int i, num;
15457
Jacek Luczak564c5be2008-05-03 18:41:23 +020015458 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15459 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015460 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015461 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015462 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15463 return;
15464 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15465 if (num < 0)
15466 return;
15467 for (i = 0; i < num; i++) {
15468 unsigned int mute;
15469 if (srcs[i] == dac || srcs[i] == 0x15)
15470 mute = AMP_IN_UNMUTE(i);
15471 else
15472 mute = AMP_IN_MUTE(i);
15473 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15474 mute);
15475 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015476}
15477
15478static void alc861_auto_init_multi_out(struct hda_codec *codec)
15479{
15480 struct alc_spec *spec = codec->spec;
15481 int i;
15482
15483 for (i = 0; i < spec->autocfg.line_outs; i++) {
15484 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015485 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015486 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015487 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015488 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015489 }
15490}
15491
15492static void alc861_auto_init_hp_out(struct hda_codec *codec)
15493{
15494 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015495
Takashi Iwai15870f02009-10-05 08:25:13 +020015496 if (spec->autocfg.hp_outs)
15497 alc861_auto_set_output_and_unmute(codec,
15498 spec->autocfg.hp_pins[0],
15499 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015500 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015501 if (spec->autocfg.speaker_outs)
15502 alc861_auto_set_output_and_unmute(codec,
15503 spec->autocfg.speaker_pins[0],
15504 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015505 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015506}
15507
15508static void alc861_auto_init_analog_input(struct hda_codec *codec)
15509{
15510 struct alc_spec *spec = codec->spec;
15511 int i;
15512
15513 for (i = 0; i < AUTO_PIN_LAST; i++) {
15514 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010015515 if (nid >= 0x0c && nid <= 0x11)
15516 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010015517 }
15518}
15519
15520/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015521/* return 1 if successful, 0 if the proper config is not found,
15522 * or a negative error code
15523 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015524static int alc861_parse_auto_config(struct hda_codec *codec)
15525{
15526 struct alc_spec *spec = codec->spec;
15527 int err;
15528 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15529
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015530 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15531 alc861_ignore);
15532 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015533 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015534 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015535 return 0; /* can't find valid BIOS pin config */
15536
Takashi Iwai1c209302009-07-22 15:17:45 +020015537 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015538 if (err < 0)
15539 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015540 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015541 if (err < 0)
15542 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015543 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015544 if (err < 0)
15545 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015546 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015547 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015548 return err;
15549
15550 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15551
Takashi Iwai757899a2010-07-30 10:48:14 +020015552 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015553
Takashi Iwai603c4012008-07-30 15:01:44 +020015554 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015555 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015556
Takashi Iwaid88897e2008-10-31 15:01:37 +010015557 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015558
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015559 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015560 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015561
15562 spec->adc_nids = alc861_adc_nids;
15563 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015564 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015565
Kailang Yang6227cdc2010-02-25 08:36:52 +010015566 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015567
Kailang Yangdf694da2005-12-05 19:42:22 +010015568 return 1;
15569}
15570
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015571/* additional initialization for auto-configuration model */
15572static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015573{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015574 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015575 alc861_auto_init_multi_out(codec);
15576 alc861_auto_init_hp_out(codec);
15577 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015578 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015579 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015580 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015581}
15582
Takashi Iwaicb53c622007-08-10 17:21:45 +020015583#ifdef CONFIG_SND_HDA_POWER_SAVE
15584static struct hda_amp_list alc861_loopbacks[] = {
15585 { 0x15, HDA_INPUT, 0 },
15586 { 0x15, HDA_INPUT, 1 },
15587 { 0x15, HDA_INPUT, 2 },
15588 { 0x15, HDA_INPUT, 3 },
15589 { } /* end */
15590};
15591#endif
15592
Kailang Yangdf694da2005-12-05 19:42:22 +010015593
15594/*
15595 * configuration and preset
15596 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015597static const char *alc861_models[ALC861_MODEL_LAST] = {
15598 [ALC861_3ST] = "3stack",
15599 [ALC660_3ST] = "3stack-660",
15600 [ALC861_3ST_DIG] = "3stack-dig",
15601 [ALC861_6ST_DIG] = "6stack-dig",
15602 [ALC861_UNIWILL_M31] = "uniwill-m31",
15603 [ALC861_TOSHIBA] = "toshiba",
15604 [ALC861_ASUS] = "asus",
15605 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15606 [ALC861_AUTO] = "auto",
15607};
15608
15609static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015610 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015611 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15612 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15613 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015614 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015615 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015616 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015617 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15618 * Any other models that need this preset?
15619 */
15620 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015621 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15622 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015623 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15624 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15625 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15626 /* FIXME: the below seems conflict */
15627 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15628 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15629 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015630 {}
15631};
15632
15633static struct alc_config_preset alc861_presets[] = {
15634 [ALC861_3ST] = {
15635 .mixers = { alc861_3ST_mixer },
15636 .init_verbs = { alc861_threestack_init_verbs },
15637 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15638 .dac_nids = alc861_dac_nids,
15639 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15640 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015641 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015642 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15643 .adc_nids = alc861_adc_nids,
15644 .input_mux = &alc861_capture_source,
15645 },
15646 [ALC861_3ST_DIG] = {
15647 .mixers = { alc861_base_mixer },
15648 .init_verbs = { alc861_threestack_init_verbs },
15649 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15650 .dac_nids = alc861_dac_nids,
15651 .dig_out_nid = ALC861_DIGOUT_NID,
15652 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15653 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015654 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015655 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15656 .adc_nids = alc861_adc_nids,
15657 .input_mux = &alc861_capture_source,
15658 },
15659 [ALC861_6ST_DIG] = {
15660 .mixers = { alc861_base_mixer },
15661 .init_verbs = { alc861_base_init_verbs },
15662 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15663 .dac_nids = alc861_dac_nids,
15664 .dig_out_nid = ALC861_DIGOUT_NID,
15665 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15666 .channel_mode = alc861_8ch_modes,
15667 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15668 .adc_nids = alc861_adc_nids,
15669 .input_mux = &alc861_capture_source,
15670 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015671 [ALC660_3ST] = {
15672 .mixers = { alc861_3ST_mixer },
15673 .init_verbs = { alc861_threestack_init_verbs },
15674 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15675 .dac_nids = alc660_dac_nids,
15676 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15677 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015678 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015679 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15680 .adc_nids = alc861_adc_nids,
15681 .input_mux = &alc861_capture_source,
15682 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015683 [ALC861_UNIWILL_M31] = {
15684 .mixers = { alc861_uniwill_m31_mixer },
15685 .init_verbs = { alc861_uniwill_m31_init_verbs },
15686 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15687 .dac_nids = alc861_dac_nids,
15688 .dig_out_nid = ALC861_DIGOUT_NID,
15689 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15690 .channel_mode = alc861_uniwill_m31_modes,
15691 .need_dac_fix = 1,
15692 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15693 .adc_nids = alc861_adc_nids,
15694 .input_mux = &alc861_capture_source,
15695 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015696 [ALC861_TOSHIBA] = {
15697 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015698 .init_verbs = { alc861_base_init_verbs,
15699 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015700 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15701 .dac_nids = alc861_dac_nids,
15702 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15703 .channel_mode = alc883_3ST_2ch_modes,
15704 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15705 .adc_nids = alc861_adc_nids,
15706 .input_mux = &alc861_capture_source,
15707 .unsol_event = alc861_toshiba_unsol_event,
15708 .init_hook = alc861_toshiba_automute,
15709 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015710 [ALC861_ASUS] = {
15711 .mixers = { alc861_asus_mixer },
15712 .init_verbs = { alc861_asus_init_verbs },
15713 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15714 .dac_nids = alc861_dac_nids,
15715 .dig_out_nid = ALC861_DIGOUT_NID,
15716 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15717 .channel_mode = alc861_asus_modes,
15718 .need_dac_fix = 1,
15719 .hp_nid = 0x06,
15720 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15721 .adc_nids = alc861_adc_nids,
15722 .input_mux = &alc861_capture_source,
15723 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015724 [ALC861_ASUS_LAPTOP] = {
15725 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15726 .init_verbs = { alc861_asus_init_verbs,
15727 alc861_asus_laptop_init_verbs },
15728 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15729 .dac_nids = alc861_dac_nids,
15730 .dig_out_nid = ALC861_DIGOUT_NID,
15731 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15732 .channel_mode = alc883_3ST_2ch_modes,
15733 .need_dac_fix = 1,
15734 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15735 .adc_nids = alc861_adc_nids,
15736 .input_mux = &alc861_capture_source,
15737 },
15738};
Kailang Yangdf694da2005-12-05 19:42:22 +010015739
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015740/* Pin config fixes */
15741enum {
15742 PINFIX_FSC_AMILO_PI1505,
15743};
15744
15745static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
15746 { 0x0b, 0x0221101f }, /* HP */
15747 { 0x0f, 0x90170310 }, /* speaker */
15748 { }
15749};
15750
15751static const struct alc_fixup alc861_fixups[] = {
15752 [PINFIX_FSC_AMILO_PI1505] = {
15753 .pins = alc861_fsc_amilo_pi1505_pinfix
15754 },
15755};
15756
15757static struct snd_pci_quirk alc861_fixup_tbl[] = {
15758 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15759 {}
15760};
Kailang Yangdf694da2005-12-05 19:42:22 +010015761
15762static int patch_alc861(struct hda_codec *codec)
15763{
15764 struct alc_spec *spec;
15765 int board_config;
15766 int err;
15767
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015768 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015769 if (spec == NULL)
15770 return -ENOMEM;
15771
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015772 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015773
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015774 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15775 alc861_models,
15776 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015777
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015778 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015779 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15780 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015781 board_config = ALC861_AUTO;
15782 }
15783
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015784 if (board_config == ALC861_AUTO)
15785 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015786
Kailang Yangdf694da2005-12-05 19:42:22 +010015787 if (board_config == ALC861_AUTO) {
15788 /* automatic parse from the BIOS config */
15789 err = alc861_parse_auto_config(codec);
15790 if (err < 0) {
15791 alc_free(codec);
15792 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015793 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015794 printk(KERN_INFO
15795 "hda_codec: Cannot set up configuration "
15796 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015797 board_config = ALC861_3ST_DIG;
15798 }
15799 }
15800
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015801 err = snd_hda_attach_beep_device(codec, 0x23);
15802 if (err < 0) {
15803 alc_free(codec);
15804 return err;
15805 }
15806
Kailang Yangdf694da2005-12-05 19:42:22 +010015807 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015808 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015809
Kailang Yangdf694da2005-12-05 19:42:22 +010015810 spec->stream_analog_playback = &alc861_pcm_analog_playback;
15811 spec->stream_analog_capture = &alc861_pcm_analog_capture;
15812
Kailang Yangdf694da2005-12-05 19:42:22 +010015813 spec->stream_digital_playback = &alc861_pcm_digital_playback;
15814 spec->stream_digital_capture = &alc861_pcm_digital_capture;
15815
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015816 if (!spec->cap_mixer)
15817 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015818 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15819
Takashi Iwai2134ea42008-01-10 16:53:55 +010015820 spec->vmaster_nid = 0x03;
15821
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015822 if (board_config == ALC861_AUTO)
15823 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
15824
Kailang Yangdf694da2005-12-05 19:42:22 +010015825 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015826 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015827 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015828#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015829 spec->power_hook = alc_power_eapd;
15830#endif
15831 }
15832#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015833 if (!spec->loopback.amplist)
15834 spec->loopback.amplist = alc861_loopbacks;
15835#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015836
Kailang Yangdf694da2005-12-05 19:42:22 +010015837 return 0;
15838}
15839
15840/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015841 * ALC861-VD support
15842 *
15843 * Based on ALC882
15844 *
15845 * In addition, an independent DAC
15846 */
15847#define ALC861VD_DIGOUT_NID 0x06
15848
15849static hda_nid_t alc861vd_dac_nids[4] = {
15850 /* front, surr, clfe, side surr */
15851 0x02, 0x03, 0x04, 0x05
15852};
15853
15854/* dac_nids for ALC660vd are in a different order - according to
15855 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015856 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015857 * of ALC660vd codecs, but for now there is only 3stack mixer
15858 * - and it is the same as in 861vd.
15859 * adc_nids in ALC660vd are (is) the same as in 861vd
15860 */
15861static hda_nid_t alc660vd_dac_nids[3] = {
15862 /* front, rear, clfe, rear_surr */
15863 0x02, 0x04, 0x03
15864};
15865
15866static hda_nid_t alc861vd_adc_nids[1] = {
15867 /* ADC0 */
15868 0x09,
15869};
15870
Takashi Iwaie1406342008-02-11 18:32:32 +010015871static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15872
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015873/* input MUX */
15874/* FIXME: should be a matrix-type input source selection */
15875static struct hda_input_mux alc861vd_capture_source = {
15876 .num_items = 4,
15877 .items = {
15878 { "Mic", 0x0 },
15879 { "Front Mic", 0x1 },
15880 { "Line", 0x2 },
15881 { "CD", 0x4 },
15882 },
15883};
15884
Kailang Yang272a5272007-05-14 11:00:38 +020015885static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015886 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015887 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015888 { "Ext Mic", 0x0 },
15889 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015890 },
15891};
15892
Kailang Yangd1a991a2007-08-15 16:21:59 +020015893static struct hda_input_mux alc861vd_hp_capture_source = {
15894 .num_items = 2,
15895 .items = {
15896 { "Front Mic", 0x0 },
15897 { "ATAPI Mic", 0x1 },
15898 },
15899};
15900
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015901/*
15902 * 2ch mode
15903 */
15904static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15905 { 2, NULL }
15906};
15907
15908/*
15909 * 6ch mode
15910 */
15911static struct hda_verb alc861vd_6stack_ch6_init[] = {
15912 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15913 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15914 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15915 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15916 { } /* end */
15917};
15918
15919/*
15920 * 8ch mode
15921 */
15922static struct hda_verb alc861vd_6stack_ch8_init[] = {
15923 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15924 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15925 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15926 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15927 { } /* end */
15928};
15929
15930static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15931 { 6, alc861vd_6stack_ch6_init },
15932 { 8, alc861vd_6stack_ch8_init },
15933};
15934
15935static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15936 {
15937 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15938 .name = "Channel Mode",
15939 .info = alc_ch_mode_info,
15940 .get = alc_ch_mode_get,
15941 .put = alc_ch_mode_put,
15942 },
15943 { } /* end */
15944};
15945
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015946/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15947 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15948 */
15949static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15950 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15951 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15952
15953 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15954 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15955
15956 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15957 HDA_OUTPUT),
15958 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15959 HDA_OUTPUT),
15960 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15961 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15962
15963 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15964 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15965
15966 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15967
15968 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15969 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15970 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15971
15972 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15973 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15974 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15975
15976 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15977 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15978
15979 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15980 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15981
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015982 { } /* end */
15983};
15984
15985static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15986 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15987 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15988
15989 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15990
15991 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15992 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15993 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15994
15995 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15996 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15997 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15998
15999 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16000 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16001
16002 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16003 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16004
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016005 { } /* end */
16006};
16007
Kailang Yangbdd148a2007-05-08 15:19:08 +020016008static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16009 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16010 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16011 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16012
16013 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16014
16015 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16016 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16017 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16018
16019 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16020 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16021 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16022
16023 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16024 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16025
16026 { } /* end */
16027};
16028
Tobin Davisb419f342008-03-07 11:57:51 +010016029/* Pin assignment: Speaker=0x14, HP = 0x15,
16030 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016031 */
16032static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016033 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16034 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016035 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16036 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010016037 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16038 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16039 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16040 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16041 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16042 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016043 { } /* end */
16044};
16045
Kailang Yangd1a991a2007-08-15 16:21:59 +020016046/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16047 * Front Mic=0x18, ATAPI Mic = 0x19,
16048 */
16049static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16050 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16051 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16052 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16053 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16054 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16055 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16056 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16057 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016058
Kailang Yangd1a991a2007-08-15 16:21:59 +020016059 { } /* end */
16060};
16061
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016062/*
16063 * generic initialization of ADC, input mixers and output mixers
16064 */
16065static struct hda_verb alc861vd_volume_init_verbs[] = {
16066 /*
16067 * Unmute ADC0 and set the default input to mic-in
16068 */
16069 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16070 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16071
16072 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16073 * the analog-loopback mixer widget
16074 */
16075 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016076 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16077 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16078 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16079 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16080 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016081
16082 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016087
16088 /*
16089 * Set up output mixers (0x02 - 0x05)
16090 */
16091 /* set vol=0 to output mixers */
16092 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16093 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16094 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16095 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16096
16097 /* set up input amps for analog loopback */
16098 /* Amp Indices: DAC = 0, mixer = 1 */
16099 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16100 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16101 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16102 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16103 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16104 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16105 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16106 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16107
16108 { }
16109};
16110
16111/*
16112 * 3-stack pin configuration:
16113 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16114 */
16115static struct hda_verb alc861vd_3stack_init_verbs[] = {
16116 /*
16117 * Set pin mode and muting
16118 */
16119 /* set front pin widgets 0x14 for output */
16120 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16121 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16122 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16123
16124 /* Mic (rear) pin: input vref at 80% */
16125 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16126 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16127 /* Front Mic pin: input vref at 80% */
16128 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16129 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16130 /* Line In pin: input */
16131 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16132 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16133 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16134 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16135 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16136 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16137 /* CD pin widget for input */
16138 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16139
16140 { }
16141};
16142
16143/*
16144 * 6-stack pin configuration:
16145 */
16146static struct hda_verb alc861vd_6stack_init_verbs[] = {
16147 /*
16148 * Set pin mode and muting
16149 */
16150 /* set front pin widgets 0x14 for output */
16151 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16152 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16153 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16154
16155 /* Rear Pin: output 1 (0x0d) */
16156 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16157 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16158 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16159 /* CLFE Pin: output 2 (0x0e) */
16160 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16161 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16162 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16163 /* Side Pin: output 3 (0x0f) */
16164 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16165 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16166 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16167
16168 /* Mic (rear) pin: input vref at 80% */
16169 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16170 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16171 /* Front Mic pin: input vref at 80% */
16172 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16173 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16174 /* Line In pin: input */
16175 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16176 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16177 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16178 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16179 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16180 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16181 /* CD pin widget for input */
16182 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16183
16184 { }
16185};
16186
Kailang Yangbdd148a2007-05-08 15:19:08 +020016187static struct hda_verb alc861vd_eapd_verbs[] = {
16188 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16189 { }
16190};
16191
Kailang Yangf9423e72008-05-27 12:32:25 +020016192static struct hda_verb alc660vd_eapd_verbs[] = {
16193 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16194 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16195 { }
16196};
16197
Kailang Yangbdd148a2007-05-08 15:19:08 +020016198static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16199 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16200 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16201 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16202 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016203 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016204 {}
16205};
16206
Kailang Yangbdd148a2007-05-08 15:19:08 +020016207static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16208{
16209 unsigned int present;
16210 unsigned char bits;
16211
Wu Fengguang864f92b2009-11-18 12:38:02 +080016212 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016213 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016214
Takashi Iwai47fd8302007-08-10 17:11:07 +020016215 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16216 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016217}
16218
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016219static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016220{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016221 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016222 spec->autocfg.hp_pins[0] = 0x1b;
16223 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016224}
16225
16226static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16227{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016228 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016229 alc861vd_lenovo_mic_automute(codec);
16230}
16231
16232static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16233 unsigned int res)
16234{
16235 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016236 case ALC880_MIC_EVENT:
16237 alc861vd_lenovo_mic_automute(codec);
16238 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016239 default:
16240 alc_automute_amp_unsol_event(codec, res);
16241 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016242 }
16243}
16244
Kailang Yang272a5272007-05-14 11:00:38 +020016245static struct hda_verb alc861vd_dallas_verbs[] = {
16246 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16247 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16248 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16249 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16250
16251 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16252 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16253 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16254 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16255 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16256 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16257 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16258 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016259
Kailang Yang272a5272007-05-14 11:00:38 +020016260 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16261 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16262 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16263 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16264 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16265 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16266 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16267 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16268
16269 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16270 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16271 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16272 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16273 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16274 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16275 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16276 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16277
16278 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16279 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16280 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16281 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16282
16283 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016284 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016285 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16286
16287 { } /* end */
16288};
16289
16290/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016291static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016292{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016293 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016294
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016295 spec->autocfg.hp_pins[0] = 0x15;
16296 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016297}
16298
Takashi Iwaicb53c622007-08-10 17:21:45 +020016299#ifdef CONFIG_SND_HDA_POWER_SAVE
16300#define alc861vd_loopbacks alc880_loopbacks
16301#endif
16302
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016303/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016304#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16305#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16306#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16307#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16308
16309/*
16310 * configuration and preset
16311 */
16312static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16313 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016314 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016315 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016316 [ALC861VD_3ST] = "3stack",
16317 [ALC861VD_3ST_DIG] = "3stack-digout",
16318 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016319 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016320 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016321 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016322 [ALC861VD_AUTO] = "auto",
16323};
16324
16325static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016326 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16327 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016328 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016329 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016330 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016331 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016332 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016333 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016334 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016335 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016336 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016337 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016338 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016339 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016340 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016341 {}
16342};
16343
16344static struct alc_config_preset alc861vd_presets[] = {
16345 [ALC660VD_3ST] = {
16346 .mixers = { alc861vd_3st_mixer },
16347 .init_verbs = { alc861vd_volume_init_verbs,
16348 alc861vd_3stack_init_verbs },
16349 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16350 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016351 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16352 .channel_mode = alc861vd_3stack_2ch_modes,
16353 .input_mux = &alc861vd_capture_source,
16354 },
Mike Crash6963f842007-06-25 12:12:51 +020016355 [ALC660VD_3ST_DIG] = {
16356 .mixers = { alc861vd_3st_mixer },
16357 .init_verbs = { alc861vd_volume_init_verbs,
16358 alc861vd_3stack_init_verbs },
16359 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16360 .dac_nids = alc660vd_dac_nids,
16361 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016362 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16363 .channel_mode = alc861vd_3stack_2ch_modes,
16364 .input_mux = &alc861vd_capture_source,
16365 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016366 [ALC861VD_3ST] = {
16367 .mixers = { alc861vd_3st_mixer },
16368 .init_verbs = { alc861vd_volume_init_verbs,
16369 alc861vd_3stack_init_verbs },
16370 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16371 .dac_nids = alc861vd_dac_nids,
16372 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16373 .channel_mode = alc861vd_3stack_2ch_modes,
16374 .input_mux = &alc861vd_capture_source,
16375 },
16376 [ALC861VD_3ST_DIG] = {
16377 .mixers = { alc861vd_3st_mixer },
16378 .init_verbs = { alc861vd_volume_init_verbs,
16379 alc861vd_3stack_init_verbs },
16380 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16381 .dac_nids = alc861vd_dac_nids,
16382 .dig_out_nid = ALC861VD_DIGOUT_NID,
16383 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16384 .channel_mode = alc861vd_3stack_2ch_modes,
16385 .input_mux = &alc861vd_capture_source,
16386 },
16387 [ALC861VD_6ST_DIG] = {
16388 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16389 .init_verbs = { alc861vd_volume_init_verbs,
16390 alc861vd_6stack_init_verbs },
16391 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16392 .dac_nids = alc861vd_dac_nids,
16393 .dig_out_nid = ALC861VD_DIGOUT_NID,
16394 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16395 .channel_mode = alc861vd_6stack_modes,
16396 .input_mux = &alc861vd_capture_source,
16397 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016398 [ALC861VD_LENOVO] = {
16399 .mixers = { alc861vd_lenovo_mixer },
16400 .init_verbs = { alc861vd_volume_init_verbs,
16401 alc861vd_3stack_init_verbs,
16402 alc861vd_eapd_verbs,
16403 alc861vd_lenovo_unsol_verbs },
16404 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16405 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016406 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16407 .channel_mode = alc861vd_3stack_2ch_modes,
16408 .input_mux = &alc861vd_capture_source,
16409 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016410 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016411 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016412 },
Kailang Yang272a5272007-05-14 11:00:38 +020016413 [ALC861VD_DALLAS] = {
16414 .mixers = { alc861vd_dallas_mixer },
16415 .init_verbs = { alc861vd_dallas_verbs },
16416 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16417 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016418 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16419 .channel_mode = alc861vd_3stack_2ch_modes,
16420 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016421 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016422 .setup = alc861vd_dallas_setup,
16423 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016424 },
16425 [ALC861VD_HP] = {
16426 .mixers = { alc861vd_hp_mixer },
16427 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16428 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16429 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016430 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016431 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16432 .channel_mode = alc861vd_3stack_2ch_modes,
16433 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016434 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016435 .setup = alc861vd_dallas_setup,
16436 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016437 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016438 [ALC660VD_ASUS_V1S] = {
16439 .mixers = { alc861vd_lenovo_mixer },
16440 .init_verbs = { alc861vd_volume_init_verbs,
16441 alc861vd_3stack_init_verbs,
16442 alc861vd_eapd_verbs,
16443 alc861vd_lenovo_unsol_verbs },
16444 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16445 .dac_nids = alc660vd_dac_nids,
16446 .dig_out_nid = ALC861VD_DIGOUT_NID,
16447 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16448 .channel_mode = alc861vd_3stack_2ch_modes,
16449 .input_mux = &alc861vd_capture_source,
16450 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016451 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016452 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016453 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016454};
16455
16456/*
16457 * BIOS auto configuration
16458 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016459static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16460 const struct auto_pin_cfg *cfg)
16461{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016462 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016463}
16464
16465
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016466static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16467 hda_nid_t nid, int pin_type, int dac_idx)
16468{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016469 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016470}
16471
16472static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16473{
16474 struct alc_spec *spec = codec->spec;
16475 int i;
16476
16477 for (i = 0; i <= HDA_SIDE; i++) {
16478 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016479 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016480 if (nid)
16481 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016482 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016483 }
16484}
16485
16486
16487static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16488{
16489 struct alc_spec *spec = codec->spec;
16490 hda_nid_t pin;
16491
16492 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016493 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016494 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016495 pin = spec->autocfg.speaker_pins[0];
16496 if (pin)
16497 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016498}
16499
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016500#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16501
16502static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16503{
16504 struct alc_spec *spec = codec->spec;
16505 int i;
16506
16507 for (i = 0; i < AUTO_PIN_LAST; i++) {
16508 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020016509 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016510 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016511 if (nid != ALC861VD_PIN_CD_NID &&
16512 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016513 snd_hda_codec_write(codec, nid, 0,
16514 AC_VERB_SET_AMP_GAIN_MUTE,
16515 AMP_OUT_MUTE);
16516 }
16517 }
16518}
16519
Takashi Iwaif511b012008-08-15 16:46:42 +020016520#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16521
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016522#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16523#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16524
16525/* add playback controls from the parsed DAC table */
16526/* Based on ALC880 version. But ALC861VD has separate,
16527 * different NIDs for mute/unmute switch and volume control */
16528static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16529 const struct auto_pin_cfg *cfg)
16530{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016531 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16532 hda_nid_t nid_v, nid_s;
16533 int i, err;
16534
16535 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016536 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016537 continue;
16538 nid_v = alc861vd_idx_to_mixer_vol(
16539 alc880_dac_to_idx(
16540 spec->multiout.dac_nids[i]));
16541 nid_s = alc861vd_idx_to_mixer_switch(
16542 alc880_dac_to_idx(
16543 spec->multiout.dac_nids[i]));
16544
16545 if (i == 2) {
16546 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016547 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16548 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016549 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16550 HDA_OUTPUT));
16551 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016552 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016553 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16554 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016555 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16556 HDA_OUTPUT));
16557 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016558 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016559 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16560 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016561 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16562 HDA_INPUT));
16563 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016564 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016565 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16566 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016567 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16568 HDA_INPUT));
16569 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016570 return err;
16571 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016572 const char *pfx;
16573 if (cfg->line_outs == 1 &&
16574 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16575 if (!cfg->hp_pins)
16576 pfx = "Speaker";
16577 else
16578 pfx = "PCM";
16579 } else
16580 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016581 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016582 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16583 HDA_OUTPUT));
16584 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016585 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016586 if (cfg->line_outs == 1 &&
16587 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16588 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016589 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016590 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016591 HDA_INPUT));
16592 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016593 return err;
16594 }
16595 }
16596 return 0;
16597}
16598
16599/* add playback controls for speaker and HP outputs */
16600/* Based on ALC880 version. But ALC861VD has separate,
16601 * different NIDs for mute/unmute switch and volume control */
16602static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16603 hda_nid_t pin, const char *pfx)
16604{
16605 hda_nid_t nid_v, nid_s;
16606 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016607
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016608 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016609 return 0;
16610
16611 if (alc880_is_fixed_pin(pin)) {
16612 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16613 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016614 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016615 spec->multiout.hp_nid = nid_v;
16616 else
16617 spec->multiout.extra_out_nid[0] = nid_v;
16618 /* control HP volume/switch on the output mixer amp */
16619 nid_v = alc861vd_idx_to_mixer_vol(
16620 alc880_fixed_pin_idx(pin));
16621 nid_s = alc861vd_idx_to_mixer_switch(
16622 alc880_fixed_pin_idx(pin));
16623
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016624 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016625 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16626 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016627 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016628 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016629 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16630 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016631 return err;
16632 } else if (alc880_is_multi_pin(pin)) {
16633 /* set manual connection */
16634 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016635 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016636 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16637 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016638 return err;
16639 }
16640 return 0;
16641}
16642
16643/* parse the BIOS configuration and set up the alc_spec
16644 * return 1 if successful, 0 if the proper config is not found,
16645 * or a negative error code
16646 * Based on ALC880 version - had to change it to override
16647 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16648static int alc861vd_parse_auto_config(struct hda_codec *codec)
16649{
16650 struct alc_spec *spec = codec->spec;
16651 int err;
16652 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
16653
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016654 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16655 alc861vd_ignore);
16656 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016657 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016658 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016659 return 0; /* can't find valid BIOS pin config */
16660
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016661 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16662 if (err < 0)
16663 return err;
16664 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16665 if (err < 0)
16666 return err;
16667 err = alc861vd_auto_create_extra_out(spec,
16668 spec->autocfg.speaker_pins[0],
16669 "Speaker");
16670 if (err < 0)
16671 return err;
16672 err = alc861vd_auto_create_extra_out(spec,
16673 spec->autocfg.hp_pins[0],
16674 "Headphone");
16675 if (err < 0)
16676 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016677 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016678 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016679 return err;
16680
16681 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16682
Takashi Iwai757899a2010-07-30 10:48:14 +020016683 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016684
Takashi Iwai603c4012008-07-30 15:01:44 +020016685 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016686 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016687
Takashi Iwaid88897e2008-10-31 15:01:37 +010016688 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016689
16690 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016691 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016692
Takashi Iwai776e1842007-08-29 15:07:11 +020016693 err = alc_auto_add_mic_boost(codec);
16694 if (err < 0)
16695 return err;
16696
Kailang Yang6227cdc2010-02-25 08:36:52 +010016697 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016698
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016699 return 1;
16700}
16701
16702/* additional initialization for auto-configuration model */
16703static void alc861vd_auto_init(struct hda_codec *codec)
16704{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016705 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016706 alc861vd_auto_init_multi_out(codec);
16707 alc861vd_auto_init_hp_out(codec);
16708 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016709 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016710 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016711 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016712 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016713}
16714
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016715enum {
16716 ALC660VD_FIX_ASUS_GPIO1
16717};
16718
16719/* reset GPIO1 */
16720static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
16721 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16722 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16723 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16724 { }
16725};
16726
16727static const struct alc_fixup alc861vd_fixups[] = {
16728 [ALC660VD_FIX_ASUS_GPIO1] = {
16729 .verbs = alc660vd_fix_asus_gpio1_verbs,
16730 },
16731};
16732
16733static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
16734 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16735 {}
16736};
16737
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016738static int patch_alc861vd(struct hda_codec *codec)
16739{
16740 struct alc_spec *spec;
16741 int err, board_config;
16742
16743 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16744 if (spec == NULL)
16745 return -ENOMEM;
16746
16747 codec->spec = spec;
16748
16749 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16750 alc861vd_models,
16751 alc861vd_cfg_tbl);
16752
16753 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016754 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16755 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016756 board_config = ALC861VD_AUTO;
16757 }
16758
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016759 if (board_config == ALC861VD_AUTO)
16760 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016761
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016762 if (board_config == ALC861VD_AUTO) {
16763 /* automatic parse from the BIOS config */
16764 err = alc861vd_parse_auto_config(codec);
16765 if (err < 0) {
16766 alc_free(codec);
16767 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016768 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016769 printk(KERN_INFO
16770 "hda_codec: Cannot set up configuration "
16771 "from BIOS. Using base mode...\n");
16772 board_config = ALC861VD_3ST;
16773 }
16774 }
16775
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016776 err = snd_hda_attach_beep_device(codec, 0x23);
16777 if (err < 0) {
16778 alc_free(codec);
16779 return err;
16780 }
16781
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016782 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016783 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016784
Kailang Yang2f893282008-05-27 12:14:47 +020016785 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016786 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016787 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016788 }
16789
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016790 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16791 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16792
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016793 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16794 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16795
Takashi Iwaidd704692009-08-11 08:45:11 +020016796 if (!spec->adc_nids) {
16797 spec->adc_nids = alc861vd_adc_nids;
16798 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16799 }
16800 if (!spec->capsrc_nids)
16801 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016802
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016803 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016804 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016805
Takashi Iwai2134ea42008-01-10 16:53:55 +010016806 spec->vmaster_nid = 0x02;
16807
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016808 if (board_config == ALC861VD_AUTO)
16809 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
16810
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016811 codec->patch_ops = alc_patch_ops;
16812
16813 if (board_config == ALC861VD_AUTO)
16814 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016815#ifdef CONFIG_SND_HDA_POWER_SAVE
16816 if (!spec->loopback.amplist)
16817 spec->loopback.amplist = alc861vd_loopbacks;
16818#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016819
16820 return 0;
16821}
16822
16823/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016824 * ALC662 support
16825 *
16826 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16827 * configuration. Each pin widget can choose any input DACs and a mixer.
16828 * Each ADC is connected from a mixer of all inputs. This makes possible
16829 * 6-channel independent captures.
16830 *
16831 * In addition, an independent DAC for the multi-playback (not used in this
16832 * driver yet).
16833 */
16834#define ALC662_DIGOUT_NID 0x06
16835#define ALC662_DIGIN_NID 0x0a
16836
16837static hda_nid_t alc662_dac_nids[4] = {
16838 /* front, rear, clfe, rear_surr */
16839 0x02, 0x03, 0x04
16840};
16841
Kailang Yang622e84c2009-04-21 07:39:04 +020016842static hda_nid_t alc272_dac_nids[2] = {
16843 0x02, 0x03
16844};
16845
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016846static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016847 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016848 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016849};
Takashi Iwaie1406342008-02-11 18:32:32 +010016850
Kailang Yang622e84c2009-04-21 07:39:04 +020016851static hda_nid_t alc272_adc_nids[1] = {
16852 /* ADC1-2 */
16853 0x08,
16854};
16855
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016856static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016857static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16858
Takashi Iwaie1406342008-02-11 18:32:32 +010016859
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016860/* input MUX */
16861/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016862static struct hda_input_mux alc662_capture_source = {
16863 .num_items = 4,
16864 .items = {
16865 { "Mic", 0x0 },
16866 { "Front Mic", 0x1 },
16867 { "Line", 0x2 },
16868 { "CD", 0x4 },
16869 },
16870};
16871
16872static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16873 .num_items = 2,
16874 .items = {
16875 { "Mic", 0x1 },
16876 { "Line", 0x2 },
16877 },
16878};
Kailang Yang291702f2007-10-16 14:28:03 +020016879
Kailang Yang6dda9f42008-05-27 12:05:31 +020016880static struct hda_input_mux alc663_capture_source = {
16881 .num_items = 3,
16882 .items = {
16883 { "Mic", 0x0 },
16884 { "Front Mic", 0x1 },
16885 { "Line", 0x2 },
16886 },
16887};
16888
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016889#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016890static struct hda_input_mux alc272_nc10_capture_source = {
16891 .num_items = 16,
16892 .items = {
16893 { "Autoselect Mic", 0x0 },
16894 { "Internal Mic", 0x1 },
16895 { "In-0x02", 0x2 },
16896 { "In-0x03", 0x3 },
16897 { "In-0x04", 0x4 },
16898 { "In-0x05", 0x5 },
16899 { "In-0x06", 0x6 },
16900 { "In-0x07", 0x7 },
16901 { "In-0x08", 0x8 },
16902 { "In-0x09", 0x9 },
16903 { "In-0x0a", 0x0a },
16904 { "In-0x0b", 0x0b },
16905 { "In-0x0c", 0x0c },
16906 { "In-0x0d", 0x0d },
16907 { "In-0x0e", 0x0e },
16908 { "In-0x0f", 0x0f },
16909 },
16910};
16911#endif
16912
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016913/*
16914 * 2ch mode
16915 */
16916static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16917 { 2, NULL }
16918};
16919
16920/*
16921 * 2ch mode
16922 */
16923static struct hda_verb alc662_3ST_ch2_init[] = {
16924 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16925 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16926 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16927 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16928 { } /* end */
16929};
16930
16931/*
16932 * 6ch mode
16933 */
16934static struct hda_verb alc662_3ST_ch6_init[] = {
16935 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16936 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16937 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16938 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16939 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16940 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16941 { } /* end */
16942};
16943
16944static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16945 { 2, alc662_3ST_ch2_init },
16946 { 6, alc662_3ST_ch6_init },
16947};
16948
16949/*
16950 * 2ch mode
16951 */
16952static struct hda_verb alc662_sixstack_ch6_init[] = {
16953 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16954 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16955 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16956 { } /* end */
16957};
16958
16959/*
16960 * 6ch mode
16961 */
16962static struct hda_verb alc662_sixstack_ch8_init[] = {
16963 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16964 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16965 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16966 { } /* end */
16967};
16968
16969static struct hda_channel_mode alc662_5stack_modes[2] = {
16970 { 2, alc662_sixstack_ch6_init },
16971 { 6, alc662_sixstack_ch8_init },
16972};
16973
16974/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16975 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16976 */
16977
16978static struct snd_kcontrol_new alc662_base_mixer[] = {
16979 /* output mixer control */
16980 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016981 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016982 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016983 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016984 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16985 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016986 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16987 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016988 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16989
16990 /*Input mixer control */
16991 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16992 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16993 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16994 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16995 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16996 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16997 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16998 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016999 { } /* end */
17000};
17001
17002static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17003 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017004 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017005 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17006 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17007 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17008 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17009 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17010 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17011 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17012 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17013 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017014 { } /* end */
17015};
17016
17017static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17018 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017019 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017020 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017021 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017022 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17023 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017024 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17025 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017026 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17027 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17028 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17029 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17030 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17031 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17032 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17033 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17034 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017035 { } /* end */
17036};
17037
17038static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17039 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17040 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017041 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17042 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017043 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17044 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17045 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17046 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17047 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017048 { } /* end */
17049};
17050
Kailang Yang291702f2007-10-16 14:28:03 +020017051static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017052 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17053 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017054
17055 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17056 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17057 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17058
17059 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17060 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17061 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17062 { } /* end */
17063};
17064
Kailang Yang8c427222008-01-10 13:03:59 +010017065static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017066 ALC262_HIPPO_MASTER_SWITCH,
17067 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017068 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017069 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17070 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017071 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17072 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17073 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17074 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17075 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17076 { } /* end */
17077};
17078
Kailang Yangf1d4e282008-08-26 14:03:29 +020017079static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17080 .ops = &snd_hda_bind_vol,
17081 .values = {
17082 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17083 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17084 0
17085 },
17086};
17087
17088static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17089 .ops = &snd_hda_bind_sw,
17090 .values = {
17091 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17092 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17093 0
17094 },
17095};
17096
Kailang Yang6dda9f42008-05-27 12:05:31 +020017097static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017098 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17099 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17100 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17101 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17102 { } /* end */
17103};
17104
17105static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17106 .ops = &snd_hda_bind_sw,
17107 .values = {
17108 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17109 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17110 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17111 0
17112 },
17113};
17114
17115static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17116 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17117 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17118 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17119 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17120 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17121 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17122
17123 { } /* end */
17124};
17125
17126static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17127 .ops = &snd_hda_bind_sw,
17128 .values = {
17129 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17130 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17131 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17132 0
17133 },
17134};
17135
17136static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17137 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17138 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17139 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17140 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17141 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17142 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17143 { } /* end */
17144};
17145
17146static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017147 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17148 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017149 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17150 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17151 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17152 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17153 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17154 { } /* end */
17155};
17156
17157static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17158 .ops = &snd_hda_bind_vol,
17159 .values = {
17160 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17161 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17162 0
17163 },
17164};
17165
17166static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17167 .ops = &snd_hda_bind_sw,
17168 .values = {
17169 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17170 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17171 0
17172 },
17173};
17174
17175static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17176 HDA_BIND_VOL("Master Playback Volume",
17177 &alc663_asus_two_bind_master_vol),
17178 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17179 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017180 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17181 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17182 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017183 { } /* end */
17184};
17185
17186static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17187 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17188 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17189 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17190 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17191 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17192 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017193 { } /* end */
17194};
17195
17196static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17197 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17198 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17199 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17200 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17201 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17202
17203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17204 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17205 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17206 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17207 { } /* end */
17208};
17209
17210static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17211 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17212 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17213 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17214
17215 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17216 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17217 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17218 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17219 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17220 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17221 { } /* end */
17222};
17223
Kailang Yangebb83ee2009-12-17 12:23:00 +010017224static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17225 .ops = &snd_hda_bind_sw,
17226 .values = {
17227 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17228 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17229 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17230 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17231 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17232 0
17233 },
17234};
17235
17236static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17237 .ops = &snd_hda_bind_sw,
17238 .values = {
17239 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17240 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17241 0
17242 },
17243};
17244
17245static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17246 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17247 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17248 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17249 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17250 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17251 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17252 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17253 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17254 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17255 { } /* end */
17256};
17257
17258static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17259 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17260 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17261 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17262 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17263 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17264 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17265 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17266 { } /* end */
17267};
17268
17269
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017270static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17271 {
17272 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17273 .name = "Channel Mode",
17274 .info = alc_ch_mode_info,
17275 .get = alc_ch_mode_get,
17276 .put = alc_ch_mode_put,
17277 },
17278 { } /* end */
17279};
17280
17281static struct hda_verb alc662_init_verbs[] = {
17282 /* ADC: mute amp left and right */
17283 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17284 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017285
Kailang Yangb60dd392007-09-20 12:50:29 +020017286 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17287 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17288 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17289 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17290 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17291 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017292
17293 /* Front Pin: output 0 (0x0c) */
17294 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17295 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17296
17297 /* Rear Pin: output 1 (0x0d) */
17298 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17299 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17300
17301 /* CLFE Pin: output 2 (0x0e) */
17302 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17303 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17304
17305 /* Mic (rear) pin: input vref at 80% */
17306 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17307 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17308 /* Front Mic pin: input vref at 80% */
17309 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17310 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17311 /* Line In pin: input */
17312 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17313 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17314 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17315 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17316 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17317 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17318 /* CD pin widget for input */
17319 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17320
17321 /* FIXME: use matrix-type input source selection */
17322 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17323 /* Input mixer */
17324 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017325 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017326
17327 /* always trun on EAPD */
17328 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17329 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17330
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017331 { }
17332};
17333
Kailang Yangcec27c82010-02-04 14:18:18 +010017334static struct hda_verb alc663_init_verbs[] = {
17335 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17336 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17337 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17338 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17339 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17340 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17341 { }
17342};
17343
17344static struct hda_verb alc272_init_verbs[] = {
17345 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17346 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17347 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17348 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17349 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17350 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17351 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17352 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17353 { }
17354};
17355
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017356static struct hda_verb alc662_sue_init_verbs[] = {
17357 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17358 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017359 {}
17360};
17361
17362static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17363 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17364 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17365 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017366};
17367
Kailang Yang8c427222008-01-10 13:03:59 +010017368/* Set Unsolicited Event*/
17369static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17370 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17371 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17372 {}
17373};
17374
Kailang Yang6dda9f42008-05-27 12:05:31 +020017375static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017376 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17377 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017378 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17379 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017380 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17381 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17382 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017383 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17384 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17385 {}
17386};
17387
Kailang Yangf1d4e282008-08-26 14:03:29 +020017388static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17389 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17390 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17391 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17392 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17393 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17394 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17395 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17396 {}
17397};
17398
17399static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17400 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17401 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17402 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17403 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17404 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17405 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17406 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17407 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17408 {}
17409};
17410
17411static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17412 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17413 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17414 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17415 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17416 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17417 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17418 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17419 {}
17420};
17421
17422static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17423 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17424 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17425 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17426 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17427 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17428 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17429 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17430 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17431 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17432 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17433 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17434 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17435 {}
17436};
17437
17438static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17439 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17440 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17441 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17442 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17443 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17444 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17445 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17446 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17447 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17448 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17449 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17450 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17451 {}
17452};
17453
Kailang Yang6dda9f42008-05-27 12:05:31 +020017454static struct hda_verb alc663_g71v_init_verbs[] = {
17455 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17456 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17457 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17458
17459 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17460 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17461 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17462
17463 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17464 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17465 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17466 {}
17467};
17468
17469static struct hda_verb alc663_g50v_init_verbs[] = {
17470 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17471 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17472 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17473
17474 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17475 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17476 {}
17477};
17478
Kailang Yangf1d4e282008-08-26 14:03:29 +020017479static struct hda_verb alc662_ecs_init_verbs[] = {
17480 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17481 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17482 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17483 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17484 {}
17485};
17486
Kailang Yang622e84c2009-04-21 07:39:04 +020017487static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17488 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17489 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17490 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17491 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17492 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17493 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17494 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17495 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17496 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17497 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17498 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17499 {}
17500};
17501
17502static struct hda_verb alc272_dell_init_verbs[] = {
17503 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17504 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17505 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17506 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17507 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17508 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17509 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17510 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17511 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17512 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17513 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17514 {}
17515};
17516
Kailang Yangebb83ee2009-12-17 12:23:00 +010017517static struct hda_verb alc663_mode7_init_verbs[] = {
17518 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17519 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17520 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17521 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17522 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17523 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17524 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17525 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17526 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17527 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17528 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17529 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17530 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17531 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17532 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17533 {}
17534};
17535
17536static struct hda_verb alc663_mode8_init_verbs[] = {
17537 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17538 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17539 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17540 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17541 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17542 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17543 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17544 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17545 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17546 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17547 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17548 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17549 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17550 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17551 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17552 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17553 {}
17554};
17555
Kailang Yangf1d4e282008-08-26 14:03:29 +020017556static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17557 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17558 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17559 { } /* end */
17560};
17561
Kailang Yang622e84c2009-04-21 07:39:04 +020017562static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17563 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17564 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17565 { } /* end */
17566};
17567
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017568static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17569{
17570 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017571 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017572
Wu Fengguang864f92b2009-11-18 12:38:02 +080017573 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017574 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017575
Takashi Iwai47fd8302007-08-10 17:11:07 +020017576 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17577 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017578}
17579
17580static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17581{
17582 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017583 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017584
Wu Fengguang864f92b2009-11-18 12:38:02 +080017585 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017586 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017587
Takashi Iwai47fd8302007-08-10 17:11:07 +020017588 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17589 HDA_AMP_MUTE, bits);
17590 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17591 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017592}
17593
17594static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17595 unsigned int res)
17596{
17597 if ((res >> 26) == ALC880_HP_EVENT)
17598 alc662_lenovo_101e_all_automute(codec);
17599 if ((res >> 26) == ALC880_FRONT_EVENT)
17600 alc662_lenovo_101e_ispeaker_automute(codec);
17601}
17602
Kailang Yang291702f2007-10-16 14:28:03 +020017603/* unsolicited event for HP jack sensing */
17604static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17605 unsigned int res)
17606{
Kailang Yang291702f2007-10-16 14:28:03 +020017607 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017608 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020017609 else
17610 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020017611}
17612
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017613static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017614{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017615 struct alc_spec *spec = codec->spec;
17616
17617 alc262_hippo1_setup(codec);
17618 spec->ext_mic.pin = 0x18;
17619 spec->ext_mic.mux_idx = 0;
17620 spec->int_mic.pin = 0x19;
17621 spec->int_mic.mux_idx = 1;
17622 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017623}
17624
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017625static void alc662_eeepc_inithook(struct hda_codec *codec)
17626{
17627 alc262_hippo_automute(codec);
17628 alc_mic_automute(codec);
17629}
17630
17631static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017632{
Takashi Iwai42171c12009-05-08 14:11:43 +020017633 struct alc_spec *spec = codec->spec;
17634
17635 spec->autocfg.hp_pins[0] = 0x14;
17636 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010017637}
17638
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017639#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
17640
Kailang Yang6dda9f42008-05-27 12:05:31 +020017641static void alc663_m51va_speaker_automute(struct hda_codec *codec)
17642{
17643 unsigned int present;
17644 unsigned char bits;
17645
Wu Fengguang864f92b2009-11-18 12:38:02 +080017646 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017647 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017648 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017649 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017650 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017651 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017652}
17653
17654static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
17655{
17656 unsigned int present;
17657 unsigned char bits;
17658
Wu Fengguang864f92b2009-11-18 12:38:02 +080017659 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017660 bits = present ? HDA_AMP_MUTE : 0;
17661 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017662 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017663 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017664 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017665 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017666 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017667 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017668 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017669}
17670
17671static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
17672{
17673 unsigned int present;
17674 unsigned char bits;
17675
Wu Fengguang864f92b2009-11-18 12:38:02 +080017676 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017677 bits = present ? HDA_AMP_MUTE : 0;
17678 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017679 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017680 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017681 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017682 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017683 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017684 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017685 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017686}
17687
17688static void alc662_f5z_speaker_automute(struct hda_codec *codec)
17689{
17690 unsigned int present;
17691 unsigned char bits;
17692
Wu Fengguang864f92b2009-11-18 12:38:02 +080017693 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017694 bits = present ? 0 : PIN_OUT;
17695 snd_hda_codec_write(codec, 0x14, 0,
17696 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
17697}
17698
17699static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
17700{
17701 unsigned int present1, present2;
17702
Wu Fengguang864f92b2009-11-18 12:38:02 +080017703 present1 = snd_hda_jack_detect(codec, 0x21);
17704 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017705
17706 if (present1 || present2) {
17707 snd_hda_codec_write_cache(codec, 0x14, 0,
17708 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17709 } else {
17710 snd_hda_codec_write_cache(codec, 0x14, 0,
17711 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17712 }
17713}
17714
17715static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
17716{
17717 unsigned int present1, present2;
17718
Wu Fengguang864f92b2009-11-18 12:38:02 +080017719 present1 = snd_hda_jack_detect(codec, 0x1b);
17720 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017721
17722 if (present1 || present2) {
17723 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017724 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017725 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017726 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017727 } else {
17728 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017729 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017730 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017731 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017732 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020017733}
17734
Kailang Yangebb83ee2009-12-17 12:23:00 +010017735static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
17736{
17737 unsigned int present1, present2;
17738
17739 present1 = snd_hda_codec_read(codec, 0x1b, 0,
17740 AC_VERB_GET_PIN_SENSE, 0)
17741 & AC_PINSENSE_PRESENCE;
17742 present2 = snd_hda_codec_read(codec, 0x21, 0,
17743 AC_VERB_GET_PIN_SENSE, 0)
17744 & AC_PINSENSE_PRESENCE;
17745
17746 if (present1 || present2) {
17747 snd_hda_codec_write_cache(codec, 0x14, 0,
17748 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17749 snd_hda_codec_write_cache(codec, 0x17, 0,
17750 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17751 } else {
17752 snd_hda_codec_write_cache(codec, 0x14, 0,
17753 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17754 snd_hda_codec_write_cache(codec, 0x17, 0,
17755 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17756 }
17757}
17758
17759static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
17760{
17761 unsigned int present1, present2;
17762
17763 present1 = snd_hda_codec_read(codec, 0x21, 0,
17764 AC_VERB_GET_PIN_SENSE, 0)
17765 & AC_PINSENSE_PRESENCE;
17766 present2 = snd_hda_codec_read(codec, 0x15, 0,
17767 AC_VERB_GET_PIN_SENSE, 0)
17768 & AC_PINSENSE_PRESENCE;
17769
17770 if (present1 || present2) {
17771 snd_hda_codec_write_cache(codec, 0x14, 0,
17772 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17773 snd_hda_codec_write_cache(codec, 0x17, 0,
17774 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17775 } else {
17776 snd_hda_codec_write_cache(codec, 0x14, 0,
17777 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17778 snd_hda_codec_write_cache(codec, 0x17, 0,
17779 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17780 }
17781}
17782
Kailang Yang6dda9f42008-05-27 12:05:31 +020017783static void alc663_m51va_unsol_event(struct hda_codec *codec,
17784 unsigned int res)
17785{
17786 switch (res >> 26) {
17787 case ALC880_HP_EVENT:
17788 alc663_m51va_speaker_automute(codec);
17789 break;
17790 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017791 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017792 break;
17793 }
17794}
17795
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017796static void alc663_m51va_setup(struct hda_codec *codec)
17797{
17798 struct alc_spec *spec = codec->spec;
17799 spec->ext_mic.pin = 0x18;
17800 spec->ext_mic.mux_idx = 0;
17801 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017802 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017803 spec->auto_mic = 1;
17804}
17805
Kailang Yang6dda9f42008-05-27 12:05:31 +020017806static void alc663_m51va_inithook(struct hda_codec *codec)
17807{
17808 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017809 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017810}
17811
Kailang Yangf1d4e282008-08-26 14:03:29 +020017812/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017813#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017814
17815static void alc663_mode1_setup(struct hda_codec *codec)
17816{
17817 struct alc_spec *spec = codec->spec;
17818 spec->ext_mic.pin = 0x18;
17819 spec->ext_mic.mux_idx = 0;
17820 spec->int_mic.pin = 0x19;
17821 spec->int_mic.mux_idx = 1;
17822 spec->auto_mic = 1;
17823}
17824
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017825#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017826
Kailang Yangf1d4e282008-08-26 14:03:29 +020017827/* ***************** Mode2 ******************************/
17828static void alc662_mode2_unsol_event(struct hda_codec *codec,
17829 unsigned int res)
17830{
17831 switch (res >> 26) {
17832 case ALC880_HP_EVENT:
17833 alc662_f5z_speaker_automute(codec);
17834 break;
17835 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017836 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017837 break;
17838 }
17839}
17840
Kailang Yangebb83ee2009-12-17 12:23:00 +010017841#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017842
Kailang Yangf1d4e282008-08-26 14:03:29 +020017843static void alc662_mode2_inithook(struct hda_codec *codec)
17844{
17845 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017846 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017847}
17848/* ***************** Mode3 ******************************/
17849static void alc663_mode3_unsol_event(struct hda_codec *codec,
17850 unsigned int res)
17851{
17852 switch (res >> 26) {
17853 case ALC880_HP_EVENT:
17854 alc663_two_hp_m1_speaker_automute(codec);
17855 break;
17856 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017857 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017858 break;
17859 }
17860}
17861
Kailang Yangebb83ee2009-12-17 12:23:00 +010017862#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017863
Kailang Yangf1d4e282008-08-26 14:03:29 +020017864static void alc663_mode3_inithook(struct hda_codec *codec)
17865{
17866 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017867 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017868}
17869/* ***************** Mode4 ******************************/
17870static void alc663_mode4_unsol_event(struct hda_codec *codec,
17871 unsigned int res)
17872{
17873 switch (res >> 26) {
17874 case ALC880_HP_EVENT:
17875 alc663_21jd_two_speaker_automute(codec);
17876 break;
17877 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017878 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017879 break;
17880 }
17881}
17882
Kailang Yangebb83ee2009-12-17 12:23:00 +010017883#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017884
Kailang Yangf1d4e282008-08-26 14:03:29 +020017885static void alc663_mode4_inithook(struct hda_codec *codec)
17886{
17887 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017888 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017889}
17890/* ***************** Mode5 ******************************/
17891static void alc663_mode5_unsol_event(struct hda_codec *codec,
17892 unsigned int res)
17893{
17894 switch (res >> 26) {
17895 case ALC880_HP_EVENT:
17896 alc663_15jd_two_speaker_automute(codec);
17897 break;
17898 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017899 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017900 break;
17901 }
17902}
17903
Kailang Yangebb83ee2009-12-17 12:23:00 +010017904#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017905
Kailang Yangf1d4e282008-08-26 14:03:29 +020017906static void alc663_mode5_inithook(struct hda_codec *codec)
17907{
17908 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017909 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017910}
17911/* ***************** Mode6 ******************************/
17912static void alc663_mode6_unsol_event(struct hda_codec *codec,
17913 unsigned int res)
17914{
17915 switch (res >> 26) {
17916 case ALC880_HP_EVENT:
17917 alc663_two_hp_m2_speaker_automute(codec);
17918 break;
17919 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017920 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017921 break;
17922 }
17923}
17924
Kailang Yangebb83ee2009-12-17 12:23:00 +010017925#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017926
Kailang Yangf1d4e282008-08-26 14:03:29 +020017927static void alc663_mode6_inithook(struct hda_codec *codec)
17928{
17929 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017930 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017931}
17932
Kailang Yangebb83ee2009-12-17 12:23:00 +010017933/* ***************** Mode7 ******************************/
17934static void alc663_mode7_unsol_event(struct hda_codec *codec,
17935 unsigned int res)
17936{
17937 switch (res >> 26) {
17938 case ALC880_HP_EVENT:
17939 alc663_two_hp_m7_speaker_automute(codec);
17940 break;
17941 case ALC880_MIC_EVENT:
17942 alc_mic_automute(codec);
17943 break;
17944 }
17945}
17946
17947#define alc663_mode7_setup alc663_mode1_setup
17948
17949static void alc663_mode7_inithook(struct hda_codec *codec)
17950{
17951 alc663_two_hp_m7_speaker_automute(codec);
17952 alc_mic_automute(codec);
17953}
17954
17955/* ***************** Mode8 ******************************/
17956static void alc663_mode8_unsol_event(struct hda_codec *codec,
17957 unsigned int res)
17958{
17959 switch (res >> 26) {
17960 case ALC880_HP_EVENT:
17961 alc663_two_hp_m8_speaker_automute(codec);
17962 break;
17963 case ALC880_MIC_EVENT:
17964 alc_mic_automute(codec);
17965 break;
17966 }
17967}
17968
17969#define alc663_mode8_setup alc663_m51va_setup
17970
17971static void alc663_mode8_inithook(struct hda_codec *codec)
17972{
17973 alc663_two_hp_m8_speaker_automute(codec);
17974 alc_mic_automute(codec);
17975}
17976
Kailang Yang6dda9f42008-05-27 12:05:31 +020017977static void alc663_g71v_hp_automute(struct hda_codec *codec)
17978{
17979 unsigned int present;
17980 unsigned char bits;
17981
Wu Fengguang864f92b2009-11-18 12:38:02 +080017982 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017983 bits = present ? HDA_AMP_MUTE : 0;
17984 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17985 HDA_AMP_MUTE, bits);
17986 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17987 HDA_AMP_MUTE, bits);
17988}
17989
17990static void alc663_g71v_front_automute(struct hda_codec *codec)
17991{
17992 unsigned int present;
17993 unsigned char bits;
17994
Wu Fengguang864f92b2009-11-18 12:38:02 +080017995 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017996 bits = present ? HDA_AMP_MUTE : 0;
17997 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17998 HDA_AMP_MUTE, bits);
17999}
18000
18001static void alc663_g71v_unsol_event(struct hda_codec *codec,
18002 unsigned int res)
18003{
18004 switch (res >> 26) {
18005 case ALC880_HP_EVENT:
18006 alc663_g71v_hp_automute(codec);
18007 break;
18008 case ALC880_FRONT_EVENT:
18009 alc663_g71v_front_automute(codec);
18010 break;
18011 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018012 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018013 break;
18014 }
18015}
18016
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018017#define alc663_g71v_setup alc663_m51va_setup
18018
Kailang Yang6dda9f42008-05-27 12:05:31 +020018019static void alc663_g71v_inithook(struct hda_codec *codec)
18020{
18021 alc663_g71v_front_automute(codec);
18022 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018023 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018024}
18025
18026static void alc663_g50v_unsol_event(struct hda_codec *codec,
18027 unsigned int res)
18028{
18029 switch (res >> 26) {
18030 case ALC880_HP_EVENT:
18031 alc663_m51va_speaker_automute(codec);
18032 break;
18033 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018034 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018035 break;
18036 }
18037}
18038
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018039#define alc663_g50v_setup alc663_m51va_setup
18040
Kailang Yang6dda9f42008-05-27 12:05:31 +020018041static void alc663_g50v_inithook(struct hda_codec *codec)
18042{
18043 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018044 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018045}
18046
Kailang Yangf1d4e282008-08-26 14:03:29 +020018047static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18048 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018049 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018050
18051 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
18052 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18053 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18054
18055 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18056 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18057 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18058 { } /* end */
18059};
18060
Chris Pockelé9541ba12009-05-12 08:08:53 +020018061static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18062 /* Master Playback automatically created from Speaker and Headphone */
18063 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18064 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18065 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18066 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18067
18068 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18069 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18070 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18071
18072 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18073 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18074 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18075 { } /* end */
18076};
18077
Takashi Iwaicb53c622007-08-10 17:21:45 +020018078#ifdef CONFIG_SND_HDA_POWER_SAVE
18079#define alc662_loopbacks alc880_loopbacks
18080#endif
18081
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018082
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018083/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018084#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18085#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18086#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18087#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18088
18089/*
18090 * configuration and preset
18091 */
18092static const char *alc662_models[ALC662_MODEL_LAST] = {
18093 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18094 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18095 [ALC662_3ST_6ch] = "3stack-6ch",
18096 [ALC662_5ST_DIG] = "6stack-dig",
18097 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018098 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018099 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018100 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018101 [ALC663_ASUS_M51VA] = "m51va",
18102 [ALC663_ASUS_G71V] = "g71v",
18103 [ALC663_ASUS_H13] = "h13",
18104 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018105 [ALC663_ASUS_MODE1] = "asus-mode1",
18106 [ALC662_ASUS_MODE2] = "asus-mode2",
18107 [ALC663_ASUS_MODE3] = "asus-mode3",
18108 [ALC663_ASUS_MODE4] = "asus-mode4",
18109 [ALC663_ASUS_MODE5] = "asus-mode5",
18110 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018111 [ALC663_ASUS_MODE7] = "asus-mode7",
18112 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018113 [ALC272_DELL] = "dell",
18114 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018115 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018116 [ALC662_AUTO] = "auto",
18117};
18118
18119static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018120 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018121 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18122 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018123 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18124 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018125 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018126 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18127 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18128 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18129 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018130 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18131 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018132 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018133 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18134 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18135 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18136 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18137 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018138 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018139 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18140 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018141 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18142 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18143 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18144 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018145 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018146 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18147 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18148 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018149 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18150 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18151 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18152 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018153 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018154 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18155 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018156 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018157 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18158 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18159 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018160 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018161 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018162 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18163 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018164 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18165 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18166 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018167 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018168 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18169 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018170 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018171 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018172 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018173 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18174 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18175 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018176 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018177 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18178 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018179 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018180 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018181 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018182 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018183 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18184 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018185 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018186 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018187 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18188 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018189 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018190 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018191 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018192 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018193 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018194 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018195 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18196 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018197 {}
18198};
18199
18200static struct alc_config_preset alc662_presets[] = {
18201 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018202 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018203 .init_verbs = { alc662_init_verbs },
18204 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18205 .dac_nids = alc662_dac_nids,
18206 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018207 .dig_in_nid = ALC662_DIGIN_NID,
18208 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18209 .channel_mode = alc662_3ST_2ch_modes,
18210 .input_mux = &alc662_capture_source,
18211 },
18212 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018213 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018214 .init_verbs = { alc662_init_verbs },
18215 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18216 .dac_nids = alc662_dac_nids,
18217 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018218 .dig_in_nid = ALC662_DIGIN_NID,
18219 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18220 .channel_mode = alc662_3ST_6ch_modes,
18221 .need_dac_fix = 1,
18222 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018223 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018224 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018225 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018226 .init_verbs = { alc662_init_verbs },
18227 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18228 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018229 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18230 .channel_mode = alc662_3ST_6ch_modes,
18231 .need_dac_fix = 1,
18232 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018233 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018234 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018235 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018236 .init_verbs = { alc662_init_verbs },
18237 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18238 .dac_nids = alc662_dac_nids,
18239 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018240 .dig_in_nid = ALC662_DIGIN_NID,
18241 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18242 .channel_mode = alc662_5stack_modes,
18243 .input_mux = &alc662_capture_source,
18244 },
18245 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018246 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018247 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18248 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18249 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018250 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18251 .channel_mode = alc662_3ST_2ch_modes,
18252 .input_mux = &alc662_lenovo_101e_capture_source,
18253 .unsol_event = alc662_lenovo_101e_unsol_event,
18254 .init_hook = alc662_lenovo_101e_all_automute,
18255 },
Kailang Yang291702f2007-10-16 14:28:03 +020018256 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018257 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018258 .init_verbs = { alc662_init_verbs,
18259 alc662_eeepc_sue_init_verbs },
18260 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18261 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018262 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18263 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018264 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018265 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018266 .init_hook = alc662_eeepc_inithook,
18267 },
Kailang Yang8c427222008-01-10 13:03:59 +010018268 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018269 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018270 alc662_chmode_mixer },
18271 .init_verbs = { alc662_init_verbs,
18272 alc662_eeepc_ep20_sue_init_verbs },
18273 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18274 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018275 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18276 .channel_mode = alc662_3ST_6ch_modes,
18277 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018278 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018279 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018280 .init_hook = alc662_eeepc_ep20_inithook,
18281 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018282 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018283 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018284 .init_verbs = { alc662_init_verbs,
18285 alc662_ecs_init_verbs },
18286 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18287 .dac_nids = alc662_dac_nids,
18288 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18289 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018291 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018292 .init_hook = alc662_eeepc_inithook,
18293 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018294 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018295 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018296 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18297 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18298 .dac_nids = alc662_dac_nids,
18299 .dig_out_nid = ALC662_DIGOUT_NID,
18300 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18301 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018302 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018303 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018304 .init_hook = alc663_m51va_inithook,
18305 },
18306 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018307 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018308 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18309 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18310 .dac_nids = alc662_dac_nids,
18311 .dig_out_nid = ALC662_DIGOUT_NID,
18312 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18313 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018314 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018315 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018316 .init_hook = alc663_g71v_inithook,
18317 },
18318 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018319 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018320 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18321 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18322 .dac_nids = alc662_dac_nids,
18323 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18324 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018325 .unsol_event = alc663_m51va_unsol_event,
18326 .init_hook = alc663_m51va_inithook,
18327 },
18328 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018329 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018330 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18331 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18332 .dac_nids = alc662_dac_nids,
18333 .dig_out_nid = ALC662_DIGOUT_NID,
18334 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18335 .channel_mode = alc662_3ST_6ch_modes,
18336 .input_mux = &alc663_capture_source,
18337 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018338 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018339 .init_hook = alc663_g50v_inithook,
18340 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018341 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018342 .mixers = { alc663_m51va_mixer },
18343 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018344 .init_verbs = { alc662_init_verbs,
18345 alc663_21jd_amic_init_verbs },
18346 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18347 .hp_nid = 0x03,
18348 .dac_nids = alc662_dac_nids,
18349 .dig_out_nid = ALC662_DIGOUT_NID,
18350 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18351 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018352 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018353 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018354 .init_hook = alc663_mode1_inithook,
18355 },
18356 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018357 .mixers = { alc662_1bjd_mixer },
18358 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018359 .init_verbs = { alc662_init_verbs,
18360 alc662_1bjd_amic_init_verbs },
18361 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18362 .dac_nids = alc662_dac_nids,
18363 .dig_out_nid = ALC662_DIGOUT_NID,
18364 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18365 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018366 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018367 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018368 .init_hook = alc662_mode2_inithook,
18369 },
18370 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018371 .mixers = { alc663_two_hp_m1_mixer },
18372 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018373 .init_verbs = { alc662_init_verbs,
18374 alc663_two_hp_amic_m1_init_verbs },
18375 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18376 .hp_nid = 0x03,
18377 .dac_nids = alc662_dac_nids,
18378 .dig_out_nid = ALC662_DIGOUT_NID,
18379 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18380 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018381 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018382 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018383 .init_hook = alc663_mode3_inithook,
18384 },
18385 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018386 .mixers = { alc663_asus_21jd_clfe_mixer },
18387 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018388 .init_verbs = { alc662_init_verbs,
18389 alc663_21jd_amic_init_verbs},
18390 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18391 .hp_nid = 0x03,
18392 .dac_nids = alc662_dac_nids,
18393 .dig_out_nid = ALC662_DIGOUT_NID,
18394 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18395 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018396 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018397 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018398 .init_hook = alc663_mode4_inithook,
18399 },
18400 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018401 .mixers = { alc663_asus_15jd_clfe_mixer },
18402 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018403 .init_verbs = { alc662_init_verbs,
18404 alc663_15jd_amic_init_verbs },
18405 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18406 .hp_nid = 0x03,
18407 .dac_nids = alc662_dac_nids,
18408 .dig_out_nid = ALC662_DIGOUT_NID,
18409 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18410 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018411 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018412 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018413 .init_hook = alc663_mode5_inithook,
18414 },
18415 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018416 .mixers = { alc663_two_hp_m2_mixer },
18417 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018418 .init_verbs = { alc662_init_verbs,
18419 alc663_two_hp_amic_m2_init_verbs },
18420 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18421 .hp_nid = 0x03,
18422 .dac_nids = alc662_dac_nids,
18423 .dig_out_nid = ALC662_DIGOUT_NID,
18424 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18425 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018426 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018427 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018428 .init_hook = alc663_mode6_inithook,
18429 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018430 [ALC663_ASUS_MODE7] = {
18431 .mixers = { alc663_mode7_mixer },
18432 .cap_mixer = alc662_auto_capture_mixer,
18433 .init_verbs = { alc662_init_verbs,
18434 alc663_mode7_init_verbs },
18435 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18436 .hp_nid = 0x03,
18437 .dac_nids = alc662_dac_nids,
18438 .dig_out_nid = ALC662_DIGOUT_NID,
18439 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18440 .channel_mode = alc662_3ST_2ch_modes,
18441 .unsol_event = alc663_mode7_unsol_event,
18442 .setup = alc663_mode7_setup,
18443 .init_hook = alc663_mode7_inithook,
18444 },
18445 [ALC663_ASUS_MODE8] = {
18446 .mixers = { alc663_mode8_mixer },
18447 .cap_mixer = alc662_auto_capture_mixer,
18448 .init_verbs = { alc662_init_verbs,
18449 alc663_mode8_init_verbs },
18450 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18451 .hp_nid = 0x03,
18452 .dac_nids = alc662_dac_nids,
18453 .dig_out_nid = ALC662_DIGOUT_NID,
18454 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18455 .channel_mode = alc662_3ST_2ch_modes,
18456 .unsol_event = alc663_mode8_unsol_event,
18457 .setup = alc663_mode8_setup,
18458 .init_hook = alc663_mode8_inithook,
18459 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018460 [ALC272_DELL] = {
18461 .mixers = { alc663_m51va_mixer },
18462 .cap_mixer = alc272_auto_capture_mixer,
18463 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18464 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18465 .dac_nids = alc662_dac_nids,
18466 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18467 .adc_nids = alc272_adc_nids,
18468 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18469 .capsrc_nids = alc272_capsrc_nids,
18470 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018471 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018472 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018473 .init_hook = alc663_m51va_inithook,
18474 },
18475 [ALC272_DELL_ZM1] = {
18476 .mixers = { alc663_m51va_mixer },
18477 .cap_mixer = alc662_auto_capture_mixer,
18478 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18479 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18480 .dac_nids = alc662_dac_nids,
18481 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18482 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018483 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018484 .capsrc_nids = alc662_capsrc_nids,
18485 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018486 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018487 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018488 .init_hook = alc663_m51va_inithook,
18489 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018490 [ALC272_SAMSUNG_NC10] = {
18491 .mixers = { alc272_nc10_mixer },
18492 .init_verbs = { alc662_init_verbs,
18493 alc663_21jd_amic_init_verbs },
18494 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18495 .dac_nids = alc272_dac_nids,
18496 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18497 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018498 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018499 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018500 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018501 .init_hook = alc663_mode4_inithook,
18502 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018503};
18504
18505
18506/*
18507 * BIOS auto configuration
18508 */
18509
Takashi Iwai7085ec12009-10-02 09:03:58 +020018510/* convert from MIX nid to DAC */
18511static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18512{
18513 if (nid == 0x0f)
18514 return 0x02;
18515 else if (nid >= 0x0c && nid <= 0x0e)
18516 return nid - 0x0c + 0x02;
18517 else
18518 return 0;
18519}
18520
18521/* get MIX nid connected to the given pin targeted to DAC */
18522static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18523 hda_nid_t dac)
18524{
18525 hda_nid_t mix[4];
18526 int i, num;
18527
18528 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18529 for (i = 0; i < num; i++) {
18530 if (alc662_mix_to_dac(mix[i]) == dac)
18531 return mix[i];
18532 }
18533 return 0;
18534}
18535
18536/* look for an empty DAC slot */
18537static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18538{
18539 struct alc_spec *spec = codec->spec;
18540 hda_nid_t srcs[5];
18541 int i, j, num;
18542
18543 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18544 if (num < 0)
18545 return 0;
18546 for (i = 0; i < num; i++) {
18547 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18548 if (!nid)
18549 continue;
18550 for (j = 0; j < spec->multiout.num_dacs; j++)
18551 if (spec->multiout.dac_nids[j] == nid)
18552 break;
18553 if (j >= spec->multiout.num_dacs)
18554 return nid;
18555 }
18556 return 0;
18557}
18558
18559/* fill in the dac_nids table from the parsed pin configuration */
18560static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18561 const struct auto_pin_cfg *cfg)
18562{
18563 struct alc_spec *spec = codec->spec;
18564 int i;
18565 hda_nid_t dac;
18566
18567 spec->multiout.dac_nids = spec->private_dac_nids;
18568 for (i = 0; i < cfg->line_outs; i++) {
18569 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18570 if (!dac)
18571 continue;
18572 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18573 }
18574 return 0;
18575}
18576
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018577static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018578 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018579{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018580 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018581 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18582}
18583
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018584static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018585 hda_nid_t nid, unsigned int chs)
18586{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018587 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018588 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18589}
18590
18591#define alc662_add_stereo_vol(spec, pfx, nid) \
18592 alc662_add_vol_ctl(spec, pfx, nid, 3)
18593#define alc662_add_stereo_sw(spec, pfx, nid) \
18594 alc662_add_sw_ctl(spec, pfx, nid, 3)
18595
18596/* add playback controls from the parsed DAC table */
18597static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18598 const struct auto_pin_cfg *cfg)
18599{
18600 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018601 static const char *chname[4] = {
18602 "Front", "Surround", NULL /*CLFE*/, "Side"
18603 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018604 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018605 int i, err;
18606
18607 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018608 nid = spec->multiout.dac_nids[i];
18609 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018610 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018611 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
18612 if (!mix)
18613 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018614 if (i == 2) {
18615 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018616 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018617 if (err < 0)
18618 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018619 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018620 if (err < 0)
18621 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018622 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018623 if (err < 0)
18624 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018625 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018626 if (err < 0)
18627 return err;
18628 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018629 const char *pfx;
18630 if (cfg->line_outs == 1 &&
18631 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018632 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018633 pfx = "Speaker";
18634 else
18635 pfx = "PCM";
18636 } else
18637 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018638 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018639 if (err < 0)
18640 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018641 if (cfg->line_outs == 1 &&
18642 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
18643 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020018644 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018645 if (err < 0)
18646 return err;
18647 }
18648 }
18649 return 0;
18650}
18651
18652/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018653/* return DAC nid if any new DAC is assigned */
18654static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018655 const char *pfx)
18656{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018657 struct alc_spec *spec = codec->spec;
18658 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018659 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018660
18661 if (!pin)
18662 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018663 nid = alc662_look_for_dac(codec, pin);
18664 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018665 /* the corresponding DAC is already occupied */
18666 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18667 return 0; /* no way */
18668 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018669 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018670 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18671 }
18672
18673 mix = alc662_dac_to_mix(codec, pin, nid);
18674 if (!mix)
18675 return 0;
18676 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
18677 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018678 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018679 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
18680 if (err < 0)
18681 return err;
18682 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018683}
18684
18685/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018686#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018687 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018688
18689static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
18690 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018691 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018692{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018693 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020018694 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018695
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018696 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018697 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018698 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
18699 if (num <= 1)
18700 return;
18701 for (i = 0; i < num; i++) {
18702 if (alc662_mix_to_dac(srcs[i]) != dac)
18703 continue;
18704 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18705 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018706 }
18707}
18708
18709static void alc662_auto_init_multi_out(struct hda_codec *codec)
18710{
18711 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018712 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018713 int i;
18714
18715 for (i = 0; i <= HDA_SIDE; i++) {
18716 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18717 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020018718 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018719 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018720 }
18721}
18722
18723static void alc662_auto_init_hp_out(struct hda_codec *codec)
18724{
18725 struct alc_spec *spec = codec->spec;
18726 hda_nid_t pin;
18727
18728 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018729 if (pin)
18730 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
18731 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018732 pin = spec->autocfg.speaker_pins[0];
18733 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018734 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
18735 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018736}
18737
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018738#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
18739
18740static void alc662_auto_init_analog_input(struct hda_codec *codec)
18741{
18742 struct alc_spec *spec = codec->spec;
18743 int i;
18744
18745 for (i = 0; i < AUTO_PIN_LAST; i++) {
18746 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020018747 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010018748 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010018749 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010018750 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018751 snd_hda_codec_write(codec, nid, 0,
18752 AC_VERB_SET_AMP_GAIN_MUTE,
18753 AMP_OUT_MUTE);
18754 }
18755 }
18756}
18757
Takashi Iwaif511b012008-08-15 16:46:42 +020018758#define alc662_auto_init_input_src alc882_auto_init_input_src
18759
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018760static int alc662_parse_auto_config(struct hda_codec *codec)
18761{
18762 struct alc_spec *spec = codec->spec;
18763 int err;
18764 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
18765
18766 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18767 alc662_ignore);
18768 if (err < 0)
18769 return err;
18770 if (!spec->autocfg.line_outs)
18771 return 0; /* can't find valid BIOS pin config */
18772
Takashi Iwai7085ec12009-10-02 09:03:58 +020018773 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018774 if (err < 0)
18775 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018776 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018777 if (err < 0)
18778 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018779 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018780 spec->autocfg.speaker_pins[0],
18781 "Speaker");
18782 if (err < 0)
18783 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018784 if (err)
18785 spec->multiout.extra_out_nid[0] = err;
18786 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018787 "Headphone");
18788 if (err < 0)
18789 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018790 if (err)
18791 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018792 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018793 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018794 return err;
18795
18796 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18797
Takashi Iwai757899a2010-07-30 10:48:14 +020018798 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018799
Takashi Iwai603c4012008-07-30 15:01:44 +020018800 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018801 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018802
18803 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018804 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018805
Kailang Yangcec27c82010-02-04 14:18:18 +010018806 add_verb(spec, alc662_init_verbs);
18807 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018808 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010018809 add_verb(spec, alc663_init_verbs);
18810
18811 if (codec->vendor_id == 0x10ec0272)
18812 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018813
18814 err = alc_auto_add_mic_boost(codec);
18815 if (err < 0)
18816 return err;
18817
Kailang Yang6227cdc2010-02-25 08:36:52 +010018818 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18819 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18820 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18821 else
18822 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018823
Takashi Iwai8c872862007-06-19 12:11:16 +020018824 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018825}
18826
18827/* additional initialization for auto-configuration model */
18828static void alc662_auto_init(struct hda_codec *codec)
18829{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018830 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018831 alc662_auto_init_multi_out(codec);
18832 alc662_auto_init_hp_out(codec);
18833 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018834 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020018835 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018836 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018837 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018838}
18839
18840static int patch_alc662(struct hda_codec *codec)
18841{
18842 struct alc_spec *spec;
18843 int err, board_config;
18844
18845 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18846 if (!spec)
18847 return -ENOMEM;
18848
18849 codec->spec = spec;
18850
Kailang Yangda00c242010-03-19 11:23:45 +010018851 alc_auto_parse_customize_define(codec);
18852
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018853 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18854
Kailang Yangc027ddc2010-03-19 11:33:06 +010018855 if (alc_read_coef_idx(codec, 0) == 0x8020)
18856 alc_codec_rename(codec, "ALC661");
18857 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
18858 codec->bus->pci->subsystem_vendor == 0x1025 &&
18859 spec->cdefine.platform_type == 1)
18860 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010018861
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018862 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18863 alc662_models,
18864 alc662_cfg_tbl);
18865 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018866 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18867 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018868 board_config = ALC662_AUTO;
18869 }
18870
18871 if (board_config == ALC662_AUTO) {
18872 /* automatic parse from the BIOS config */
18873 err = alc662_parse_auto_config(codec);
18874 if (err < 0) {
18875 alc_free(codec);
18876 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018877 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018878 printk(KERN_INFO
18879 "hda_codec: Cannot set up configuration "
18880 "from BIOS. Using base mode...\n");
18881 board_config = ALC662_3ST_2ch_DIG;
18882 }
18883 }
18884
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018885 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020018886 err = snd_hda_attach_beep_device(codec, 0x1);
18887 if (err < 0) {
18888 alc_free(codec);
18889 return err;
18890 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018891 }
18892
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018893 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018894 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018895
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018896 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18897 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18898
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018899 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18900 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18901
Takashi Iwaidd704692009-08-11 08:45:11 +020018902 if (!spec->adc_nids) {
18903 spec->adc_nids = alc662_adc_nids;
18904 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18905 }
18906 if (!spec->capsrc_nids)
18907 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018908
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018909 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018910 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018911
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018912 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010018913 switch (codec->vendor_id) {
18914 case 0x10ec0662:
18915 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18916 break;
18917 case 0x10ec0272:
18918 case 0x10ec0663:
18919 case 0x10ec0665:
18920 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18921 break;
18922 case 0x10ec0273:
18923 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18924 break;
18925 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018926 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018927 spec->vmaster_nid = 0x02;
18928
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018929 codec->patch_ops = alc_patch_ops;
18930 if (board_config == ALC662_AUTO)
18931 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018932#ifdef CONFIG_SND_HDA_POWER_SAVE
18933 if (!spec->loopback.amplist)
18934 spec->loopback.amplist = alc662_loopbacks;
18935#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018936
18937 return 0;
18938}
18939
Kailang Yang274693f2009-12-03 10:07:50 +010018940static int patch_alc888(struct hda_codec *codec)
18941{
18942 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18943 kfree(codec->chip_name);
18944 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018945 if (!codec->chip_name) {
18946 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018947 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018948 }
18949 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018950 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018951 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018952}
18953
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018954/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018955 * ALC680 support
18956 */
18957#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
18958#define alc680_modes alc260_modes
18959
18960static hda_nid_t alc680_dac_nids[3] = {
18961 /* Lout1, Lout2, hp */
18962 0x02, 0x03, 0x04
18963};
18964
18965static hda_nid_t alc680_adc_nids[3] = {
18966 /* ADC0-2 */
18967 /* DMIC, MIC, Line-in*/
18968 0x07, 0x08, 0x09
18969};
18970
18971static struct snd_kcontrol_new alc680_base_mixer[] = {
18972 /* output mixer control */
18973 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
18974 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18975 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
18976 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
18977 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
18978 { }
18979};
18980
18981static struct snd_kcontrol_new alc680_capture_mixer[] = {
18982 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
18983 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
18984 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
18985 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
18986 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
18987 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
18988 { } /* end */
18989};
18990
18991/*
18992 * generic initialization of ADC, input mixers and output mixers
18993 */
18994static struct hda_verb alc680_init_verbs[] = {
18995 /* Unmute DAC0-1 and set vol = 0 */
18996 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18997 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18998 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
18999
19000 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19001 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19002 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
19003 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
19004 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
19005
19006 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19007 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19008 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19009 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19010 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19011 { }
19012};
19013
19014/* create input playback/capture controls for the given pin */
19015static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19016 const char *ctlname, int idx)
19017{
19018 hda_nid_t dac;
19019 int err;
19020
19021 switch (nid) {
19022 case 0x14:
19023 dac = 0x02;
19024 break;
19025 case 0x15:
19026 dac = 0x03;
19027 break;
19028 case 0x16:
19029 dac = 0x04;
19030 break;
19031 default:
19032 return 0;
19033 }
19034 if (spec->multiout.dac_nids[0] != dac &&
19035 spec->multiout.dac_nids[1] != dac) {
19036 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19037 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19038 HDA_OUTPUT));
19039 if (err < 0)
19040 return err;
19041
19042 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19043 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19044
19045 if (err < 0)
19046 return err;
19047 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19048 }
19049
19050 return 0;
19051}
19052
19053/* add playback controls from the parsed DAC table */
19054static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19055 const struct auto_pin_cfg *cfg)
19056{
19057 hda_nid_t nid;
19058 int err;
19059
19060 spec->multiout.dac_nids = spec->private_dac_nids;
19061
19062 nid = cfg->line_out_pins[0];
19063 if (nid) {
19064 const char *name;
19065 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19066 name = "Speaker";
19067 else
19068 name = "Front";
19069 err = alc680_new_analog_output(spec, nid, name, 0);
19070 if (err < 0)
19071 return err;
19072 }
19073
19074 nid = cfg->speaker_pins[0];
19075 if (nid) {
19076 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19077 if (err < 0)
19078 return err;
19079 }
19080 nid = cfg->hp_pins[0];
19081 if (nid) {
19082 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19083 if (err < 0)
19084 return err;
19085 }
19086
19087 return 0;
19088}
19089
19090static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19091 hda_nid_t nid, int pin_type)
19092{
19093 alc_set_pin_output(codec, nid, pin_type);
19094}
19095
19096static void alc680_auto_init_multi_out(struct hda_codec *codec)
19097{
19098 struct alc_spec *spec = codec->spec;
19099 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19100 if (nid) {
19101 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19102 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19103 }
19104}
19105
19106static void alc680_auto_init_hp_out(struct hda_codec *codec)
19107{
19108 struct alc_spec *spec = codec->spec;
19109 hda_nid_t pin;
19110
19111 pin = spec->autocfg.hp_pins[0];
19112 if (pin)
19113 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19114 pin = spec->autocfg.speaker_pins[0];
19115 if (pin)
19116 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19117}
19118
19119/* pcm configuration: identical with ALC880 */
19120#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19121#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19122#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19123#define alc680_pcm_digital_playback alc880_pcm_digital_playback
19124
19125static struct hda_input_mux alc680_capture_source = {
19126 .num_items = 1,
19127 .items = {
19128 { "Mic", 0x0 },
19129 },
19130};
19131
19132/*
19133 * BIOS auto configuration
19134 */
19135static int alc680_parse_auto_config(struct hda_codec *codec)
19136{
19137 struct alc_spec *spec = codec->spec;
19138 int err;
19139 static hda_nid_t alc680_ignore[] = { 0 };
19140
19141 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19142 alc680_ignore);
19143 if (err < 0)
19144 return err;
19145 if (!spec->autocfg.line_outs) {
19146 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19147 spec->multiout.max_channels = 2;
19148 spec->no_analog = 1;
19149 goto dig_only;
19150 }
19151 return 0; /* can't find valid BIOS pin config */
19152 }
19153 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19154 if (err < 0)
19155 return err;
19156
19157 spec->multiout.max_channels = 2;
19158
19159 dig_only:
19160 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019161 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019162 if (spec->kctls.list)
19163 add_mixer(spec, spec->kctls.list);
19164
19165 add_verb(spec, alc680_init_verbs);
19166 spec->num_mux_defs = 1;
19167 spec->input_mux = &alc680_capture_source;
19168
19169 err = alc_auto_add_mic_boost(codec);
19170 if (err < 0)
19171 return err;
19172
19173 return 1;
19174}
19175
19176#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19177
19178/* init callback for auto-configuration model -- overriding the default init */
19179static void alc680_auto_init(struct hda_codec *codec)
19180{
19181 struct alc_spec *spec = codec->spec;
19182 alc680_auto_init_multi_out(codec);
19183 alc680_auto_init_hp_out(codec);
19184 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019185 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019186 if (spec->unsol_event)
19187 alc_inithook(codec);
19188}
19189
19190/*
19191 * configuration and preset
19192 */
19193static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019194 [ALC680_BASE] = "base",
19195 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019196};
19197
19198static struct snd_pci_quirk alc680_cfg_tbl[] = {
19199 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19200 {}
19201};
19202
19203static struct alc_config_preset alc680_presets[] = {
19204 [ALC680_BASE] = {
19205 .mixers = { alc680_base_mixer },
19206 .cap_mixer = alc680_capture_mixer,
19207 .init_verbs = { alc680_init_verbs },
19208 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19209 .dac_nids = alc680_dac_nids,
19210 .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
19211 .adc_nids = alc680_adc_nids,
19212 .hp_nid = 0x04,
19213 .dig_out_nid = ALC680_DIGOUT_NID,
19214 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19215 .channel_mode = alc680_modes,
19216 .input_mux = &alc680_capture_source,
19217 },
19218};
19219
19220static int patch_alc680(struct hda_codec *codec)
19221{
19222 struct alc_spec *spec;
19223 int board_config;
19224 int err;
19225
19226 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19227 if (spec == NULL)
19228 return -ENOMEM;
19229
19230 codec->spec = spec;
19231
19232 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19233 alc680_models,
19234 alc680_cfg_tbl);
19235
19236 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19237 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19238 codec->chip_name);
19239 board_config = ALC680_AUTO;
19240 }
19241
19242 if (board_config == ALC680_AUTO) {
19243 /* automatic parse from the BIOS config */
19244 err = alc680_parse_auto_config(codec);
19245 if (err < 0) {
19246 alc_free(codec);
19247 return err;
19248 } else if (!err) {
19249 printk(KERN_INFO
19250 "hda_codec: Cannot set up configuration "
19251 "from BIOS. Using base mode...\n");
19252 board_config = ALC680_BASE;
19253 }
19254 }
19255
19256 if (board_config != ALC680_AUTO)
19257 setup_preset(codec, &alc680_presets[board_config]);
19258
19259 spec->stream_analog_playback = &alc680_pcm_analog_playback;
19260 spec->stream_analog_capture = &alc680_pcm_analog_capture;
19261 spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
19262 spec->stream_digital_playback = &alc680_pcm_digital_playback;
19263
19264 if (!spec->adc_nids) {
19265 spec->adc_nids = alc680_adc_nids;
19266 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19267 }
19268
19269 if (!spec->cap_mixer)
19270 set_capture_mixer(codec);
19271
19272 spec->vmaster_nid = 0x02;
19273
19274 codec->patch_ops = alc_patch_ops;
19275 if (board_config == ALC680_AUTO)
19276 spec->init_hook = alc680_auto_init;
19277
19278 return 0;
19279}
19280
19281/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019282 * patch entries
19283 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019284static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019285 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019286 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019287 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019288 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019289 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019290 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019291 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019292 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019293 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019294 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019295 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19296 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19297 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019298 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019299 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019300 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19301 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019302 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019303 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019304 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019305 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019306 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019307 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019308 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019309 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019310 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019311 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019312 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019313 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019314 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019315 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019316 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019317 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019318 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019319 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019320 {} /* terminator */
19321};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019322
19323MODULE_ALIAS("snd-hda-codec-id:10ec*");
19324
19325MODULE_LICENSE("GPL");
19326MODULE_DESCRIPTION("Realtek HD-audio codec");
19327
19328static struct hda_codec_preset_list realtek_list = {
19329 .preset = snd_hda_preset_realtek,
19330 .owner = THIS_MODULE,
19331};
19332
19333static int __init patch_realtek_init(void)
19334{
19335 return snd_hda_add_codec_preset(&realtek_list);
19336}
19337
19338static void __exit patch_realtek_exit(void)
19339{
19340 snd_hda_delete_codec_preset(&realtek_list);
19341}
19342
19343module_init(patch_realtek_init)
19344module_exit(patch_realtek_exit)