blob: c8070620a4d8793a88d390a5965f916ea92047af [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
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 Woithe7cf51e482006-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 Avdoninbab282b92006-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 Woithe7cf51e482006-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 Woithe7cf51e482006-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 Woithe7cf51e482006-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 Kluin4b35d2ca2009-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 Iwai748cce42010-08-04 07:37:39 +02005169/* select or unmute the given capsrc route */
5170static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5171 int idx)
5172{
5173 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5174 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5175 HDA_AMP_MUTE, 0);
5176 } else {
5177 snd_hda_codec_write_cache(codec, cap, 0,
5178 AC_VERB_SET_CONNECT_SEL, idx);
5179 }
5180}
5181
Takashi Iwai840b64c2010-07-13 22:49:01 +02005182/* set the default connection to that pin */
5183static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5184{
5185 struct alc_spec *spec = codec->spec;
5186 int i;
5187
5188 for (i = 0; i < spec->num_adc_nids; i++) {
5189 hda_nid_t cap = spec->capsrc_nids ?
5190 spec->capsrc_nids[i] : spec->adc_nids[i];
5191 int idx;
5192
5193 idx = get_connection_index(codec, cap, pin);
5194 if (idx < 0)
5195 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005196 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005197 return i; /* return the found index */
5198 }
5199 return -1; /* not found */
5200}
5201
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005202/* choose the ADC/MUX containing the input pin and initialize the setup */
5203static void fixup_single_adc(struct hda_codec *codec)
5204{
5205 struct alc_spec *spec = codec->spec;
Frederik Deweerdtd2db09b2010-03-05 16:34:31 +01005206 hda_nid_t pin = 0;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005207 int i;
5208
5209 /* search for the input pin; there must be only one */
5210 for (i = 0; i < AUTO_PIN_LAST; i++) {
5211 if (spec->autocfg.input_pins[i]) {
5212 pin = spec->autocfg.input_pins[i];
5213 break;
5214 }
5215 }
5216 if (!pin)
5217 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005218 i = init_capsrc_for_pin(codec, pin);
5219 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005220 /* use only this ADC */
5221 if (spec->capsrc_nids)
5222 spec->capsrc_nids += i;
5223 spec->adc_nids += i;
5224 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005225 }
5226}
5227
Takashi Iwai840b64c2010-07-13 22:49:01 +02005228/* initialize dual adcs */
5229static void fixup_dual_adc_switch(struct hda_codec *codec)
5230{
5231 struct alc_spec *spec = codec->spec;
5232 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5233 init_capsrc_for_pin(codec, spec->int_mic.pin);
5234}
5235
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005236static void set_capture_mixer(struct hda_codec *codec)
5237{
5238 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005239 static struct snd_kcontrol_new *caps[2][3] = {
5240 { alc_capture_mixer_nosrc1,
5241 alc_capture_mixer_nosrc2,
5242 alc_capture_mixer_nosrc3 },
5243 { alc_capture_mixer1,
5244 alc_capture_mixer2,
5245 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005246 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005247 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005248 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005249 int num_adcs = spec->num_adc_nids;
5250 if (spec->dual_adc_switch)
5251 fixup_dual_adc_switch(codec);
5252 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005253 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005254 else if (spec->input_mux) {
5255 if (spec->input_mux->num_items > 1)
5256 mux = 1;
5257 else if (spec->input_mux->num_items == 1)
5258 fixup_single_adc(codec);
5259 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005260 if (spec->dual_adc_switch)
5261 num_adcs = 1;
5262 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005263 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005264}
5265
Takashi Iwai66946352010-03-29 17:21:45 +02005266/* fill adc_nids (and capsrc_nids) containing all active input pins */
5267static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5268 int num_nids)
5269{
5270 struct alc_spec *spec = codec->spec;
5271 int n;
5272 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5273
5274 for (n = 0; n < num_nids; n++) {
5275 hda_nid_t adc, cap;
5276 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5277 int nconns, i, j;
5278
5279 adc = nids[n];
5280 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5281 continue;
5282 cap = adc;
5283 nconns = snd_hda_get_connections(codec, cap, conn,
5284 ARRAY_SIZE(conn));
5285 if (nconns == 1) {
5286 cap = conn[0];
5287 nconns = snd_hda_get_connections(codec, cap, conn,
5288 ARRAY_SIZE(conn));
5289 }
5290 if (nconns <= 0)
5291 continue;
5292 if (!fallback_adc) {
5293 fallback_adc = adc;
5294 fallback_cap = cap;
5295 }
5296 for (i = 0; i < AUTO_PIN_LAST; i++) {
5297 hda_nid_t nid = spec->autocfg.input_pins[i];
5298 if (!nid)
5299 continue;
5300 for (j = 0; j < nconns; j++) {
5301 if (conn[j] == nid)
5302 break;
5303 }
5304 if (j >= nconns)
5305 break;
5306 }
5307 if (i >= AUTO_PIN_LAST) {
5308 int num_adcs = spec->num_adc_nids;
5309 spec->private_adc_nids[num_adcs] = adc;
5310 spec->private_capsrc_nids[num_adcs] = cap;
5311 spec->num_adc_nids++;
5312 spec->adc_nids = spec->private_adc_nids;
5313 if (adc != cap)
5314 spec->capsrc_nids = spec->private_capsrc_nids;
5315 }
5316 }
5317 if (!spec->num_adc_nids) {
5318 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005319 " using fallback 0x%x\n",
5320 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005321 spec->private_adc_nids[0] = fallback_adc;
5322 spec->adc_nids = spec->private_adc_nids;
5323 if (fallback_adc != fallback_cap) {
5324 spec->private_capsrc_nids[0] = fallback_cap;
5325 spec->capsrc_nids = spec->private_adc_nids;
5326 }
5327 }
5328}
5329
Takashi Iwai67d634c2009-11-16 15:35:59 +01005330#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005331#define set_beep_amp(spec, nid, idx, dir) \
5332 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005333
5334static struct snd_pci_quirk beep_white_list[] = {
5335 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005336 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005337 {}
5338};
5339
5340static inline int has_cdefine_beep(struct hda_codec *codec)
5341{
5342 struct alc_spec *spec = codec->spec;
5343 const struct snd_pci_quirk *q;
5344 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5345 if (q)
5346 return q->value;
5347 return spec->cdefine.enable_pcbeep;
5348}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005349#else
5350#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005351#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005352#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005353
5354/*
5355 * OK, here we have finally the patch for ALC880
5356 */
5357
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358static int patch_alc880(struct hda_codec *codec)
5359{
5360 struct alc_spec *spec;
5361 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005362 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005364 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 if (spec == NULL)
5366 return -ENOMEM;
5367
5368 codec->spec = spec;
5369
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005370 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5371 alc880_models,
5372 alc880_cfg_tbl);
5373 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005374 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5375 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005376 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 }
5378
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005379 if (board_config == ALC880_AUTO) {
5380 /* automatic parse from the BIOS config */
5381 err = alc880_parse_auto_config(codec);
5382 if (err < 0) {
5383 alc_free(codec);
5384 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005385 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005386 printk(KERN_INFO
5387 "hda_codec: Cannot set up configuration "
5388 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005389 board_config = ALC880_3ST;
5390 }
5391 }
5392
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005393 err = snd_hda_attach_beep_device(codec, 0x1);
5394 if (err < 0) {
5395 alc_free(codec);
5396 return err;
5397 }
5398
Kailang Yangdf694da2005-12-05 19:42:22 +01005399 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005400 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5403 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005404 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5407 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5408
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005409 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005410 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005411 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005412 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005413 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005414 if (wcap != AC_WID_AUD_IN) {
5415 spec->adc_nids = alc880_adc_nids_alt;
5416 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005417 } else {
5418 spec->adc_nids = alc880_adc_nids;
5419 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005420 }
5421 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005422 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005423 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Takashi Iwai2134ea42008-01-10 16:53:55 +01005425 spec->vmaster_nid = 0x0c;
5426
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005428 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005429 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005430#ifdef CONFIG_SND_HDA_POWER_SAVE
5431 if (!spec->loopback.amplist)
5432 spec->loopback.amplist = alc880_loopbacks;
5433#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
5435 return 0;
5436}
5437
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005438
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439/*
5440 * ALC260 support
5441 */
5442
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005443static hda_nid_t alc260_dac_nids[1] = {
5444 /* front */
5445 0x02,
5446};
5447
5448static hda_nid_t alc260_adc_nids[1] = {
5449 /* ADC0 */
5450 0x04,
5451};
5452
Kailang Yangdf694da2005-12-05 19:42:22 +01005453static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005454 /* ADC1 */
5455 0x05,
5456};
5457
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005458/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5459 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5460 */
5461static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005462 /* ADC0, ADC1 */
5463 0x04, 0x05
5464};
5465
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005466#define ALC260_DIGOUT_NID 0x03
5467#define ALC260_DIGIN_NID 0x06
5468
5469static struct hda_input_mux alc260_capture_source = {
5470 .num_items = 4,
5471 .items = {
5472 { "Mic", 0x0 },
5473 { "Front Mic", 0x1 },
5474 { "Line", 0x2 },
5475 { "CD", 0x4 },
5476 },
5477};
5478
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005479/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005480 * headphone jack and the internal CD lines since these are the only pins at
5481 * which audio can appear. For flexibility, also allow the option of
5482 * recording the mixer output on the second ADC (ADC0 doesn't have a
5483 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005484 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005485static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5486 {
5487 .num_items = 3,
5488 .items = {
5489 { "Mic/Line", 0x0 },
5490 { "CD", 0x4 },
5491 { "Headphone", 0x2 },
5492 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005493 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005494 {
5495 .num_items = 4,
5496 .items = {
5497 { "Mic/Line", 0x0 },
5498 { "CD", 0x4 },
5499 { "Headphone", 0x2 },
5500 { "Mixer", 0x5 },
5501 },
5502 },
5503
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005504};
5505
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005506/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5507 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005508 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005509static struct hda_input_mux alc260_acer_capture_sources[2] = {
5510 {
5511 .num_items = 4,
5512 .items = {
5513 { "Mic", 0x0 },
5514 { "Line", 0x2 },
5515 { "CD", 0x4 },
5516 { "Headphone", 0x5 },
5517 },
5518 },
5519 {
5520 .num_items = 5,
5521 .items = {
5522 { "Mic", 0x0 },
5523 { "Line", 0x2 },
5524 { "CD", 0x4 },
5525 { "Headphone", 0x6 },
5526 { "Mixer", 0x5 },
5527 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005528 },
5529};
Michael Schwingencc959482009-02-22 18:58:45 +01005530
5531/* Maxdata Favorit 100XS */
5532static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5533 {
5534 .num_items = 2,
5535 .items = {
5536 { "Line/Mic", 0x0 },
5537 { "CD", 0x4 },
5538 },
5539 },
5540 {
5541 .num_items = 3,
5542 .items = {
5543 { "Line/Mic", 0x0 },
5544 { "CD", 0x4 },
5545 { "Mixer", 0x5 },
5546 },
5547 },
5548};
5549
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550/*
5551 * This is just place-holder, so there's something for alc_build_pcms to look
5552 * at when it calculates the maximum number of channels. ALC260 has no mixer
5553 * element which allows changing the channel mode, so the verb list is
5554 * never used.
5555 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005556static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 { 2, NULL },
5558};
5559
Kailang Yangdf694da2005-12-05 19:42:22 +01005560
5561/* Mixer combinations
5562 *
5563 * basic: base_output + input + pc_beep + capture
5564 * HP: base_output + input + capture_alt
5565 * HP_3013: hp_3013 + input + capture
5566 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005567 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005568 */
5569
5570static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005571 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005572 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005573 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5574 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5575 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5576 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5577 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005578};
Kailang Yangdf694da2005-12-05 19:42:22 +01005579
5580static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5582 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5583 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5584 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5585 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5586 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5587 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5588 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 { } /* end */
5590};
5591
Takashi Iwaibec15c32008-01-28 18:16:30 +01005592/* update HP, line and mono out pins according to the master switch */
5593static void alc260_hp_master_update(struct hda_codec *codec,
5594 hda_nid_t hp, hda_nid_t line,
5595 hda_nid_t mono)
5596{
5597 struct alc_spec *spec = codec->spec;
5598 unsigned int val = spec->master_sw ? PIN_HP : 0;
5599 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005600 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005601 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005602 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005603 val);
5604 /* mono (speaker) depending on the HP jack sense */
5605 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005606 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005607 val);
5608}
5609
5610static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5611 struct snd_ctl_elem_value *ucontrol)
5612{
5613 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5614 struct alc_spec *spec = codec->spec;
5615 *ucontrol->value.integer.value = spec->master_sw;
5616 return 0;
5617}
5618
5619static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5620 struct snd_ctl_elem_value *ucontrol)
5621{
5622 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5623 struct alc_spec *spec = codec->spec;
5624 int val = !!*ucontrol->value.integer.value;
5625 hda_nid_t hp, line, mono;
5626
5627 if (val == spec->master_sw)
5628 return 0;
5629 spec->master_sw = val;
5630 hp = (kcontrol->private_value >> 16) & 0xff;
5631 line = (kcontrol->private_value >> 8) & 0xff;
5632 mono = kcontrol->private_value & 0xff;
5633 alc260_hp_master_update(codec, hp, line, mono);
5634 return 1;
5635}
5636
5637static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5638 {
5639 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5640 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005641 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005642 .info = snd_ctl_boolean_mono_info,
5643 .get = alc260_hp_master_sw_get,
5644 .put = alc260_hp_master_sw_put,
5645 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5646 },
5647 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5648 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5649 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5650 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5651 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5652 HDA_OUTPUT),
5653 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5654 { } /* end */
5655};
5656
5657static struct hda_verb alc260_hp_unsol_verbs[] = {
5658 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5659 {},
5660};
5661
5662static void alc260_hp_automute(struct hda_codec *codec)
5663{
5664 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005665
Wu Fengguang864f92b2009-11-18 12:38:02 +08005666 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005667 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5668}
5669
5670static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5671{
5672 if ((res >> 26) == ALC880_HP_EVENT)
5673 alc260_hp_automute(codec);
5674}
5675
Kailang Yangdf694da2005-12-05 19:42:22 +01005676static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005677 {
5678 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5679 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005680 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005681 .info = snd_ctl_boolean_mono_info,
5682 .get = alc260_hp_master_sw_get,
5683 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005684 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005685 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005686 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5687 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5688 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5689 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5690 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5691 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005692 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5693 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005694 { } /* end */
5695};
5696
Kailang Yang3f878302008-08-26 13:02:23 +02005697static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5698 .ops = &snd_hda_bind_vol,
5699 .values = {
5700 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5701 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5702 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5703 0
5704 },
5705};
5706
5707static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5708 .ops = &snd_hda_bind_sw,
5709 .values = {
5710 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5711 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5712 0
5713 },
5714};
5715
5716static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5717 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5718 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5719 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5720 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5721 { } /* end */
5722};
5723
Takashi Iwaibec15c32008-01-28 18:16:30 +01005724static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5725 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5726 {},
5727};
5728
5729static void alc260_hp_3013_automute(struct hda_codec *codec)
5730{
5731 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005732
Wu Fengguang864f92b2009-11-18 12:38:02 +08005733 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005734 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005735}
5736
5737static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5738 unsigned int res)
5739{
5740 if ((res >> 26) == ALC880_HP_EVENT)
5741 alc260_hp_3013_automute(codec);
5742}
5743
Kailang Yang3f878302008-08-26 13:02:23 +02005744static void alc260_hp_3012_automute(struct hda_codec *codec)
5745{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005746 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005747
Kailang Yang3f878302008-08-26 13:02:23 +02005748 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5749 bits);
5750 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5751 bits);
5752 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5753 bits);
5754}
5755
5756static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5757 unsigned int res)
5758{
5759 if ((res >> 26) == ALC880_HP_EVENT)
5760 alc260_hp_3012_automute(codec);
5761}
5762
5763/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005764 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5765 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005766static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005767 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005768 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005769 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005770 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5771 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5772 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5773 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005774 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005775 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5776 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005777 { } /* end */
5778};
5779
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005780/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5781 * versions of the ALC260 don't act on requests to enable mic bias from NID
5782 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5783 * datasheet doesn't mention this restriction. At this stage it's not clear
5784 * whether this behaviour is intentional or is a hardware bug in chip
5785 * revisions available in early 2006. Therefore for now allow the
5786 * "Headphone Jack Mode" control to span all choices, but if it turns out
5787 * that the lack of mic bias for this NID is intentional we could change the
5788 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5789 *
5790 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5791 * don't appear to make the mic bias available from the "line" jack, even
5792 * though the NID used for this jack (0x14) can supply it. The theory is
5793 * that perhaps Acer have included blocking capacitors between the ALC260
5794 * and the output jack. If this turns out to be the case for all such
5795 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5796 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005797 *
5798 * The C20x Tablet series have a mono internal speaker which is controlled
5799 * via the chip's Mono sum widget and pin complex, so include the necessary
5800 * controls for such models. On models without a "mono speaker" the control
5801 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005802 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005803static struct snd_kcontrol_new alc260_acer_mixer[] = {
5804 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5805 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005806 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005807 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005808 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005809 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005810 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005811 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5812 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5813 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5814 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5815 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5816 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5817 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5818 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005819 { } /* end */
5820};
5821
Michael Schwingencc959482009-02-22 18:58:45 +01005822/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5823 */
5824static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5825 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5826 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5827 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5828 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5829 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5830 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5831 { } /* end */
5832};
5833
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005834/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5835 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5836 */
5837static struct snd_kcontrol_new alc260_will_mixer[] = {
5838 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5839 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5840 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5841 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5842 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5843 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5844 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5845 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5846 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5847 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005848 { } /* end */
5849};
5850
5851/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5852 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5853 */
5854static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5855 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5856 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5857 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5858 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5859 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5860 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5861 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5862 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5863 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5864 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5865 { } /* end */
5866};
5867
Kailang Yangdf694da2005-12-05 19:42:22 +01005868/*
5869 * initialization verbs
5870 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871static struct hda_verb alc260_init_verbs[] = {
5872 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005873 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005875 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005877 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005879 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005881 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005883 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005885 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005887 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005889 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5890 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005891 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 /* set connection select to line in (default select for this ADC) */
5893 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005894 /* mute capture amp left and right */
5895 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5896 /* set connection select to line in (default select for this ADC) */
5897 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005898 /* set vol=0 Line-Out mixer amp left and right */
5899 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5900 /* unmute pin widget amp left and right (no gain on this amp) */
5901 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5902 /* set vol=0 HP mixer amp left and right */
5903 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5904 /* unmute pin widget amp left and right (no gain on this amp) */
5905 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5906 /* set vol=0 Mono mixer amp left and right */
5907 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5908 /* unmute pin widget amp left and right (no gain on this amp) */
5909 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5910 /* unmute LINE-2 out pin */
5911 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005912 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5913 * Line In 2 = 0x03
5914 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005915 /* mute analog inputs */
5916 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5917 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5918 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5919 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5920 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005922 /* mute Front out path */
5923 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5924 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5925 /* mute Headphone out path */
5926 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5927 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5928 /* mute Mono out path */
5929 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5930 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 { }
5932};
5933
Takashi Iwai474167d2006-05-17 17:17:43 +02005934#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005935static struct hda_verb alc260_hp_init_verbs[] = {
5936 /* Headphone and output */
5937 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5938 /* mono output */
5939 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5940 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5941 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5942 /* Mic2 (front panel) pin widget for input and vref at 80% */
5943 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5944 /* Line In pin widget for input */
5945 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5946 /* Line-2 pin widget for output */
5947 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5948 /* CD pin widget for input */
5949 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5950 /* unmute amp left and right */
5951 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5952 /* set connection select to line in (default select for this ADC) */
5953 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5954 /* unmute Line-Out mixer amp left and right (volume = 0) */
5955 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5956 /* mute pin widget amp left and right (no gain on this amp) */
5957 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5958 /* unmute HP mixer amp left and right (volume = 0) */
5959 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5960 /* mute pin widget amp left and right (no gain on this amp) */
5961 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005962 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5963 * Line In 2 = 0x03
5964 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005965 /* mute analog inputs */
5966 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5967 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5968 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5969 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5970 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005971 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5972 /* Unmute Front out path */
5973 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5974 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5975 /* Unmute Headphone out path */
5976 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5977 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5978 /* Unmute Mono out path */
5979 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5980 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5981 { }
5982};
Takashi Iwai474167d2006-05-17 17:17:43 +02005983#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005984
5985static struct hda_verb alc260_hp_3013_init_verbs[] = {
5986 /* Line out and output */
5987 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5988 /* mono output */
5989 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5990 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5991 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5992 /* Mic2 (front panel) pin widget for input and vref at 80% */
5993 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5994 /* Line In pin widget for input */
5995 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5996 /* Headphone pin widget for output */
5997 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5998 /* CD pin widget for input */
5999 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6000 /* unmute amp left and right */
6001 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6002 /* set connection select to line in (default select for this ADC) */
6003 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6004 /* unmute Line-Out mixer amp left and right (volume = 0) */
6005 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6006 /* mute pin widget amp left and right (no gain on this amp) */
6007 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6008 /* unmute HP mixer amp left and right (volume = 0) */
6009 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6010 /* mute pin widget amp left and right (no gain on this amp) */
6011 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006012 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6013 * Line In 2 = 0x03
6014 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006015 /* mute analog inputs */
6016 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6017 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6018 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6019 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6020 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006021 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6022 /* Unmute Front out path */
6023 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6024 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6025 /* Unmute Headphone out path */
6026 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6027 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6028 /* Unmute Mono out path */
6029 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6030 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6031 { }
6032};
6033
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006034/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006035 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6036 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006037 */
6038static struct hda_verb alc260_fujitsu_init_verbs[] = {
6039 /* Disable all GPIOs */
6040 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6041 /* Internal speaker is connected to headphone pin */
6042 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6043 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6044 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006045 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6046 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6047 /* Ensure all other unused pins are disabled and muted. */
6048 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6049 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006050 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006051 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006052 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006053 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6054 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6055 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006056
Jonathan Woithef7ace402006-02-28 11:46:14 +01006057 /* Disable digital (SPDIF) pins */
6058 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6059 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006060
Kailang Yangea1fb292008-08-26 12:58:38 +02006061 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006062 * when acting as an output.
6063 */
6064 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6065
6066 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006067 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6068 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6069 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6070 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6071 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6072 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6073 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6074 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6075 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006076
Jonathan Woithef7ace402006-02-28 11:46:14 +01006077 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6078 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6079 /* Unmute Line1 pin widget output buffer since it starts as an output.
6080 * If the pin mode is changed by the user the pin mode control will
6081 * take care of enabling the pin's input/output buffers as needed.
6082 * Therefore there's no need to enable the input buffer at this
6083 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006084 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006085 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006086 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006087 * mixer ctrl)
6088 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006089 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006090
Jonathan Woithef7ace402006-02-28 11:46:14 +01006091 /* Mute capture amp left and right */
6092 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006093 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006094 * in (on mic1 pin)
6095 */
6096 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006097
Jonathan Woithef7ace402006-02-28 11:46:14 +01006098 /* Do the same for the second ADC: mute capture input amp and
6099 * set ADC connection to line in (on mic1 pin)
6100 */
6101 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6102 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006103
Jonathan Woithef7ace402006-02-28 11:46:14 +01006104 /* Mute all inputs to mixer widget (even unconnected ones) */
6105 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6106 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6108 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6109 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6110 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6111 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6112 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006113
6114 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006115};
6116
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006117/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6118 * similar laptops (adapted from Fujitsu init verbs).
6119 */
6120static struct hda_verb alc260_acer_init_verbs[] = {
6121 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6122 * the headphone jack. Turn this on and rely on the standard mute
6123 * methods whenever the user wants to turn these outputs off.
6124 */
6125 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6126 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6127 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6128 /* Internal speaker/Headphone jack is connected to Line-out pin */
6129 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6130 /* Internal microphone/Mic jack is connected to Mic1 pin */
6131 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6132 /* Line In jack is connected to Line1 pin */
6133 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006134 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6135 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006136 /* Ensure all other unused pins are disabled and muted. */
6137 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6138 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006139 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6140 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6141 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6142 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6143 /* Disable digital (SPDIF) pins */
6144 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6145 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6146
Kailang Yangea1fb292008-08-26 12:58:38 +02006147 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006148 * bus when acting as outputs.
6149 */
6150 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6151 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6152
6153 /* Start with output sum widgets muted and their output gains at min */
6154 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6155 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6156 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6157 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6158 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6159 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6160 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6161 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6162 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6163
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006164 /* Unmute Line-out pin widget amp left and right
6165 * (no equiv mixer ctrl)
6166 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006167 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006168 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6169 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006170 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6171 * inputs. If the pin mode is changed by the user the pin mode control
6172 * will take care of enabling the pin's input/output buffers as needed.
6173 * Therefore there's no need to enable the input buffer at this
6174 * stage.
6175 */
6176 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6177 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6178
6179 /* Mute capture amp left and right */
6180 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6181 /* Set ADC connection select to match default mixer setting - mic
6182 * (on mic1 pin)
6183 */
6184 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6185
6186 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006187 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006188 */
6189 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006190 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006191
6192 /* Mute all inputs to mixer widget (even unconnected ones) */
6193 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6194 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6196 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6197 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6198 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6199 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6200 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6201
6202 { }
6203};
6204
Michael Schwingencc959482009-02-22 18:58:45 +01006205/* Initialisation sequence for Maxdata Favorit 100XS
6206 * (adapted from Acer init verbs).
6207 */
6208static struct hda_verb alc260_favorit100_init_verbs[] = {
6209 /* GPIO 0 enables the output jack.
6210 * Turn this on and rely on the standard mute
6211 * methods whenever the user wants to turn these outputs off.
6212 */
6213 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6214 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6215 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6216 /* Line/Mic input jack is connected to Mic1 pin */
6217 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6218 /* Ensure all other unused pins are disabled and muted. */
6219 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6220 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6221 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6222 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6223 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6224 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6225 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6226 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6227 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6228 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6229 /* Disable digital (SPDIF) pins */
6230 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6231 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6232
6233 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6234 * bus when acting as outputs.
6235 */
6236 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6237 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6238
6239 /* Start with output sum widgets muted and their output gains at min */
6240 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6241 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6242 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6243 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6244 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6245 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6246 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6247 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6248 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6249
6250 /* Unmute Line-out pin widget amp left and right
6251 * (no equiv mixer ctrl)
6252 */
6253 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6254 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6255 * inputs. If the pin mode is changed by the user the pin mode control
6256 * will take care of enabling the pin's input/output buffers as needed.
6257 * Therefore there's no need to enable the input buffer at this
6258 * stage.
6259 */
6260 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6261
6262 /* Mute capture amp left and right */
6263 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6264 /* Set ADC connection select to match default mixer setting - mic
6265 * (on mic1 pin)
6266 */
6267 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6268
6269 /* Do similar with the second ADC: mute capture input amp and
6270 * set ADC connection to mic to match ALSA's default state.
6271 */
6272 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6273 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6274
6275 /* Mute all inputs to mixer widget (even unconnected ones) */
6276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6278 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6279 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6280 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6281 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6282 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6283 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6284
6285 { }
6286};
6287
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006288static struct hda_verb alc260_will_verbs[] = {
6289 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6290 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6291 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6292 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6293 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6294 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6295 {}
6296};
6297
6298static struct hda_verb alc260_replacer_672v_verbs[] = {
6299 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6300 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6301 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6302
6303 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6304 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6305 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6306
6307 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6308 {}
6309};
6310
6311/* toggle speaker-output according to the hp-jack state */
6312static void alc260_replacer_672v_automute(struct hda_codec *codec)
6313{
6314 unsigned int present;
6315
6316 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006317 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006318 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006319 snd_hda_codec_write_cache(codec, 0x01, 0,
6320 AC_VERB_SET_GPIO_DATA, 1);
6321 snd_hda_codec_write_cache(codec, 0x0f, 0,
6322 AC_VERB_SET_PIN_WIDGET_CONTROL,
6323 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006324 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006325 snd_hda_codec_write_cache(codec, 0x01, 0,
6326 AC_VERB_SET_GPIO_DATA, 0);
6327 snd_hda_codec_write_cache(codec, 0x0f, 0,
6328 AC_VERB_SET_PIN_WIDGET_CONTROL,
6329 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006330 }
6331}
6332
6333static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6334 unsigned int res)
6335{
6336 if ((res >> 26) == ALC880_HP_EVENT)
6337 alc260_replacer_672v_automute(codec);
6338}
6339
Kailang Yang3f878302008-08-26 13:02:23 +02006340static struct hda_verb alc260_hp_dc7600_verbs[] = {
6341 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6342 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6343 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6344 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6345 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6346 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6347 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6348 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6349 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6350 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6351 {}
6352};
6353
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006354/* Test configuration for debugging, modelled after the ALC880 test
6355 * configuration.
6356 */
6357#ifdef CONFIG_SND_DEBUG
6358static hda_nid_t alc260_test_dac_nids[1] = {
6359 0x02,
6360};
6361static hda_nid_t alc260_test_adc_nids[2] = {
6362 0x04, 0x05,
6363};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006364/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006365 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006366 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006367 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006368static struct hda_input_mux alc260_test_capture_sources[2] = {
6369 {
6370 .num_items = 7,
6371 .items = {
6372 { "MIC1 pin", 0x0 },
6373 { "MIC2 pin", 0x1 },
6374 { "LINE1 pin", 0x2 },
6375 { "LINE2 pin", 0x3 },
6376 { "CD pin", 0x4 },
6377 { "LINE-OUT pin", 0x5 },
6378 { "HP-OUT pin", 0x6 },
6379 },
6380 },
6381 {
6382 .num_items = 8,
6383 .items = {
6384 { "MIC1 pin", 0x0 },
6385 { "MIC2 pin", 0x1 },
6386 { "LINE1 pin", 0x2 },
6387 { "LINE2 pin", 0x3 },
6388 { "CD pin", 0x4 },
6389 { "Mixer", 0x5 },
6390 { "LINE-OUT pin", 0x6 },
6391 { "HP-OUT pin", 0x7 },
6392 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006393 },
6394};
6395static struct snd_kcontrol_new alc260_test_mixer[] = {
6396 /* Output driver widgets */
6397 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6398 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6399 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6400 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6401 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6402 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6403
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006404 /* Modes for retasking pin widgets
6405 * Note: the ALC260 doesn't seem to act on requests to enable mic
6406 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6407 * mention this restriction. At this stage it's not clear whether
6408 * this behaviour is intentional or is a hardware bug in chip
6409 * revisions available at least up until early 2006. Therefore for
6410 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6411 * choices, but if it turns out that the lack of mic bias for these
6412 * NIDs is intentional we could change their modes from
6413 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6414 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006415 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6416 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6417 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6418 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6419 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6420 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6421
6422 /* Loopback mixer controls */
6423 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6424 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6425 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6426 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6427 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6428 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6429 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6430 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6431 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6432 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006433 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6434 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6435 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6436 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006437
6438 /* Controls for GPIO pins, assuming they are configured as outputs */
6439 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6440 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6441 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6442 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6443
Jonathan Woithe92621f12006-02-28 11:47:47 +01006444 /* Switches to allow the digital IO pins to be enabled. The datasheet
6445 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006446 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006447 */
6448 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6449 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6450
Jonathan Woithef8225f62008-01-08 12:16:54 +01006451 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6452 * this output to turn on an external amplifier.
6453 */
6454 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6455 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6456
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006457 { } /* end */
6458};
6459static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006460 /* Enable all GPIOs as outputs with an initial value of 0 */
6461 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6462 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6463 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6464
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006465 /* Enable retasking pins as output, initially without power amp */
6466 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6467 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6468 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6469 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6470 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6471 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6472
Jonathan Woithe92621f12006-02-28 11:47:47 +01006473 /* Disable digital (SPDIF) pins initially, but users can enable
6474 * them via a mixer switch. In the case of SPDIF-out, this initverb
6475 * payload also sets the generation to 0, output to be in "consumer"
6476 * PCM format, copyright asserted, no pre-emphasis and no validity
6477 * control.
6478 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006479 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6480 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6481
Kailang Yangea1fb292008-08-26 12:58:38 +02006482 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006483 * OUT1 sum bus when acting as an output.
6484 */
6485 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6486 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6487 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6488 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6489
6490 /* Start with output sum widgets muted and their output gains at min */
6491 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6492 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6493 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6494 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6495 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6496 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6497 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6498 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6499 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6500
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006501 /* Unmute retasking pin widget output buffers since the default
6502 * state appears to be output. As the pin mode is changed by the
6503 * user the pin mode control will take care of enabling the pin's
6504 * input/output buffers as needed.
6505 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006506 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6507 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6508 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6509 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6510 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6511 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6512 /* Also unmute the mono-out pin widget */
6513 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6514
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006515 /* Mute capture amp left and right */
6516 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006517 /* Set ADC connection select to match default mixer setting (mic1
6518 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006519 */
6520 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6521
6522 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006523 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006524 */
6525 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6526 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6527
6528 /* Mute all inputs to mixer widget (even unconnected ones) */
6529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6530 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6531 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6532 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6533 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6535 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6536 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6537
6538 { }
6539};
6540#endif
6541
Takashi Iwai63300792008-01-24 15:31:36 +01006542#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6543#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006545#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6546#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6547
Kailang Yangdf694da2005-12-05 19:42:22 +01006548/*
6549 * for BIOS auto-configuration
6550 */
6551
6552static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006553 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006554{
6555 hda_nid_t nid_vol;
6556 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006557 int err;
6558
6559 if (nid >= 0x0f && nid < 0x11) {
6560 nid_vol = nid - 0x7;
6561 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6562 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6563 } else if (nid == 0x11) {
6564 nid_vol = nid - 0x7;
6565 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6566 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6567 } else if (nid >= 0x12 && nid <= 0x15) {
6568 nid_vol = 0x08;
6569 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6570 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6571 } else
6572 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006573
Takashi Iwai863b4512008-10-21 17:01:47 +02006574 if (!(*vol_bits & (1 << nid_vol))) {
6575 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006576 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006577 if (err < 0)
6578 return err;
6579 *vol_bits |= (1 << nid_vol);
6580 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006581 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006582 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006583 return err;
6584 return 1;
6585}
6586
6587/* add playback controls from the parsed DAC table */
6588static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6589 const struct auto_pin_cfg *cfg)
6590{
6591 hda_nid_t nid;
6592 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006593 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006594
6595 spec->multiout.num_dacs = 1;
6596 spec->multiout.dac_nids = spec->private_dac_nids;
6597 spec->multiout.dac_nids[0] = 0x02;
6598
6599 nid = cfg->line_out_pins[0];
6600 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006601 const char *pfx;
6602 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6603 pfx = "Master";
6604 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6605 pfx = "Speaker";
6606 else
6607 pfx = "Front";
6608 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006609 if (err < 0)
6610 return err;
6611 }
6612
Takashi Iwai82bc9552006-03-21 11:24:42 +01006613 nid = cfg->speaker_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, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006616 if (err < 0)
6617 return err;
6618 }
6619
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006620 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006621 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006622 err = alc260_add_playback_controls(spec, nid, "Headphone",
6623 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006624 if (err < 0)
6625 return err;
6626 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006627 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006628}
6629
6630/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006631static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006632 const struct auto_pin_cfg *cfg)
6633{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006634 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006635}
6636
6637static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6638 hda_nid_t nid, int pin_type,
6639 int sel_idx)
6640{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006641 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006642 /* need the manual connection? */
6643 if (nid >= 0x12) {
6644 int idx = nid - 0x12;
6645 snd_hda_codec_write(codec, idx + 0x0b, 0,
6646 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006647 }
6648}
6649
6650static void alc260_auto_init_multi_out(struct hda_codec *codec)
6651{
6652 struct alc_spec *spec = codec->spec;
6653 hda_nid_t nid;
6654
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006655 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006656 if (nid) {
6657 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6658 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6659 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006660
Takashi Iwai82bc9552006-03-21 11:24:42 +01006661 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006662 if (nid)
6663 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6664
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006665 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006666 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006667 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006668}
Kailang Yangdf694da2005-12-05 19:42:22 +01006669
6670#define ALC260_PIN_CD_NID 0x16
6671static void alc260_auto_init_analog_input(struct hda_codec *codec)
6672{
6673 struct alc_spec *spec = codec->spec;
6674 int i;
6675
6676 for (i = 0; i < AUTO_PIN_LAST; i++) {
6677 hda_nid_t nid = spec->autocfg.input_pins[i];
6678 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006679 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006680 if (nid != ALC260_PIN_CD_NID &&
6681 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006682 snd_hda_codec_write(codec, nid, 0,
6683 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006684 AMP_OUT_MUTE);
6685 }
6686 }
6687}
6688
Takashi Iwai7f311a42010-04-09 17:32:23 +02006689#define alc260_auto_init_input_src alc880_auto_init_input_src
6690
Kailang Yangdf694da2005-12-05 19:42:22 +01006691/*
6692 * generic initialization of ADC, input mixers and output mixers
6693 */
6694static struct hda_verb alc260_volume_init_verbs[] = {
6695 /*
6696 * Unmute ADC0-1 and set the default input to mic-in
6697 */
6698 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6699 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6700 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6701 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006702
Kailang Yangdf694da2005-12-05 19:42:22 +01006703 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6704 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006705 * Note: PASD motherboards uses the Line In 2 as the input for
6706 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006707 */
6708 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006709 /* mute analog inputs */
6710 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6711 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6712 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6713 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6714 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006715
6716 /*
6717 * Set up output mixers (0x08 - 0x0a)
6718 */
6719 /* set vol=0 to output mixers */
6720 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6721 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6722 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6723 /* set up input amps for analog loopback */
6724 /* Amp Indices: DAC = 0, mixer = 1 */
6725 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6726 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6727 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6728 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6729 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6730 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006731
Kailang Yangdf694da2005-12-05 19:42:22 +01006732 { }
6733};
6734
6735static int alc260_parse_auto_config(struct hda_codec *codec)
6736{
6737 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006738 int err;
6739 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6740
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006741 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6742 alc260_ignore);
6743 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006744 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006745 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6746 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006747 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006748 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006749 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006750 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006751 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006752 return err;
6753
6754 spec->multiout.max_channels = 2;
6755
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006756 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006757 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006758 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006759 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006760
Takashi Iwaid88897e2008-10-31 15:01:37 +01006761 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006762
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006763 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006764 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006765
Kailang Yang6227cdc2010-02-25 08:36:52 +01006766 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006767
Kailang Yangdf694da2005-12-05 19:42:22 +01006768 return 1;
6769}
6770
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006771/* additional initialization for auto-configuration model */
6772static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006773{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006774 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006775 alc260_auto_init_multi_out(codec);
6776 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02006777 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02006778 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006779 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006780 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006781}
6782
Takashi Iwaicb53c622007-08-10 17:21:45 +02006783#ifdef CONFIG_SND_HDA_POWER_SAVE
6784static struct hda_amp_list alc260_loopbacks[] = {
6785 { 0x07, HDA_INPUT, 0 },
6786 { 0x07, HDA_INPUT, 1 },
6787 { 0x07, HDA_INPUT, 2 },
6788 { 0x07, HDA_INPUT, 3 },
6789 { 0x07, HDA_INPUT, 4 },
6790 { } /* end */
6791};
6792#endif
6793
Kailang Yangdf694da2005-12-05 19:42:22 +01006794/*
6795 * ALC260 configurations
6796 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006797static const char *alc260_models[ALC260_MODEL_LAST] = {
6798 [ALC260_BASIC] = "basic",
6799 [ALC260_HP] = "hp",
6800 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006801 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006802 [ALC260_FUJITSU_S702X] = "fujitsu",
6803 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006804 [ALC260_WILL] = "will",
6805 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006806 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006807#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006808 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006809#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006810 [ALC260_AUTO] = "auto",
6811};
6812
6813static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006814 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006815 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006816 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006817 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006818 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006819 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006820 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006821 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006822 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006823 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6824 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6825 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6826 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6827 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6828 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6829 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6830 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6831 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006832 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006833 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006834 {}
6835};
6836
Kailang Yangdf694da2005-12-05 19:42:22 +01006837static struct alc_config_preset alc260_presets[] = {
6838 [ALC260_BASIC] = {
6839 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006840 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006841 .init_verbs = { alc260_init_verbs },
6842 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6843 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006844 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01006845 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006846 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6847 .channel_mode = alc260_modes,
6848 .input_mux = &alc260_capture_source,
6849 },
6850 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006851 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006852 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006853 .init_verbs = { alc260_init_verbs,
6854 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006855 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6856 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006857 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6858 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006859 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6860 .channel_mode = alc260_modes,
6861 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006862 .unsol_event = alc260_hp_unsol_event,
6863 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006864 },
Kailang Yang3f878302008-08-26 13:02:23 +02006865 [ALC260_HP_DC7600] = {
6866 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006867 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006868 .init_verbs = { alc260_init_verbs,
6869 alc260_hp_dc7600_verbs },
6870 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6871 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006872 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6873 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006874 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6875 .channel_mode = alc260_modes,
6876 .input_mux = &alc260_capture_source,
6877 .unsol_event = alc260_hp_3012_unsol_event,
6878 .init_hook = alc260_hp_3012_automute,
6879 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006880 [ALC260_HP_3013] = {
6881 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006882 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006883 .init_verbs = { alc260_hp_3013_init_verbs,
6884 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006885 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6886 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006887 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6888 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006889 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6890 .channel_mode = alc260_modes,
6891 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006892 .unsol_event = alc260_hp_3013_unsol_event,
6893 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006894 },
6895 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006896 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006897 .init_verbs = { alc260_fujitsu_init_verbs },
6898 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6899 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006900 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6901 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006902 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6903 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006904 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6905 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006906 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006907 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006908 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006909 .init_verbs = { alc260_acer_init_verbs },
6910 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6911 .dac_nids = alc260_dac_nids,
6912 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6913 .adc_nids = alc260_dual_adc_nids,
6914 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6915 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006916 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6917 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006918 },
Michael Schwingencc959482009-02-22 18:58:45 +01006919 [ALC260_FAVORIT100] = {
6920 .mixers = { alc260_favorit100_mixer },
6921 .init_verbs = { alc260_favorit100_init_verbs },
6922 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6923 .dac_nids = alc260_dac_nids,
6924 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6925 .adc_nids = alc260_dual_adc_nids,
6926 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6927 .channel_mode = alc260_modes,
6928 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6929 .input_mux = alc260_favorit100_capture_sources,
6930 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006931 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006932 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006933 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6934 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6935 .dac_nids = alc260_dac_nids,
6936 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6937 .adc_nids = alc260_adc_nids,
6938 .dig_out_nid = ALC260_DIGOUT_NID,
6939 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6940 .channel_mode = alc260_modes,
6941 .input_mux = &alc260_capture_source,
6942 },
6943 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006944 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006945 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6946 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6947 .dac_nids = alc260_dac_nids,
6948 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6949 .adc_nids = alc260_adc_nids,
6950 .dig_out_nid = ALC260_DIGOUT_NID,
6951 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6952 .channel_mode = alc260_modes,
6953 .input_mux = &alc260_capture_source,
6954 .unsol_event = alc260_replacer_672v_unsol_event,
6955 .init_hook = alc260_replacer_672v_automute,
6956 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006957#ifdef CONFIG_SND_DEBUG
6958 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006959 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006960 .init_verbs = { alc260_test_init_verbs },
6961 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6962 .dac_nids = alc260_test_dac_nids,
6963 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6964 .adc_nids = alc260_test_adc_nids,
6965 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6966 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006967 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6968 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006969 },
6970#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006971};
6972
Linus Torvalds1da177e2005-04-16 15:20:36 -07006973static int patch_alc260(struct hda_codec *codec)
6974{
6975 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006976 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006977
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006978 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979 if (spec == NULL)
6980 return -ENOMEM;
6981
6982 codec->spec = spec;
6983
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006984 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6985 alc260_models,
6986 alc260_cfg_tbl);
6987 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006988 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006989 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006990 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006991 }
6992
Kailang Yangdf694da2005-12-05 19:42:22 +01006993 if (board_config == ALC260_AUTO) {
6994 /* automatic parse from the BIOS config */
6995 err = alc260_parse_auto_config(codec);
6996 if (err < 0) {
6997 alc_free(codec);
6998 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006999 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007000 printk(KERN_INFO
7001 "hda_codec: Cannot set up configuration "
7002 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007003 board_config = ALC260_BASIC;
7004 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007006
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007007 err = snd_hda_attach_beep_device(codec, 0x1);
7008 if (err < 0) {
7009 alc_free(codec);
7010 return err;
7011 }
7012
Kailang Yangdf694da2005-12-05 19:42:22 +01007013 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007014 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015
Linus Torvalds1da177e2005-04-16 15:20:36 -07007016 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7017 spec->stream_analog_capture = &alc260_pcm_analog_capture;
7018
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007019 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7020 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7021
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007022 if (!spec->adc_nids && spec->input_mux) {
7023 /* check whether NID 0x04 is valid */
7024 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007025 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007026 /* get type */
7027 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7028 spec->adc_nids = alc260_adc_nids_alt;
7029 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7030 } else {
7031 spec->adc_nids = alc260_adc_nids;
7032 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7033 }
7034 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007035 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007036 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007037
Takashi Iwai2134ea42008-01-10 16:53:55 +01007038 spec->vmaster_nid = 0x08;
7039
Linus Torvalds1da177e2005-04-16 15:20:36 -07007040 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007041 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007042 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007043#ifdef CONFIG_SND_HDA_POWER_SAVE
7044 if (!spec->loopback.amplist)
7045 spec->loopback.amplist = alc260_loopbacks;
7046#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047
7048 return 0;
7049}
7050
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007051
Linus Torvalds1da177e2005-04-16 15:20:36 -07007052/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007053 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054 *
7055 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7056 * configuration. Each pin widget can choose any input DACs and a mixer.
7057 * Each ADC is connected from a mixer of all inputs. This makes possible
7058 * 6-channel independent captures.
7059 *
7060 * In addition, an independent DAC for the multi-playback (not used in this
7061 * driver yet).
7062 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007063#define ALC882_DIGOUT_NID 0x06
7064#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02007065#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7066#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7067#define ALC1200_DIGOUT_NID 0x10
7068
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007070static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007071 { 8, NULL }
7072};
7073
Takashi Iwai4953550a2009-06-30 15:28:30 +02007074/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007075static hda_nid_t alc882_dac_nids[4] = {
7076 /* front, rear, clfe, rear_surr */
7077 0x02, 0x03, 0x04, 0x05
7078};
Takashi Iwai4953550a2009-06-30 15:28:30 +02007079#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007080
Takashi Iwai4953550a2009-06-30 15:28:30 +02007081/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007082#define alc882_adc_nids alc880_adc_nids
7083#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02007084#define alc883_adc_nids alc882_adc_nids_alt
7085static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7086static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7087#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088
Takashi Iwaie1406342008-02-11 18:32:32 +01007089static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7090static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007091#define alc883_capsrc_nids alc882_capsrc_nids_alt
7092static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7093#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007094
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095/* input MUX */
7096/* FIXME: should be a matrix-type input source selection */
7097
7098static struct hda_input_mux alc882_capture_source = {
7099 .num_items = 4,
7100 .items = {
7101 { "Mic", 0x0 },
7102 { "Front Mic", 0x1 },
7103 { "Line", 0x2 },
7104 { "CD", 0x4 },
7105 },
7106};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007107
Takashi Iwai4953550a2009-06-30 15:28:30 +02007108#define alc883_capture_source alc882_capture_source
7109
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007110static struct hda_input_mux alc889_capture_source = {
7111 .num_items = 3,
7112 .items = {
7113 { "Front Mic", 0x0 },
7114 { "Mic", 0x3 },
7115 { "Line", 0x2 },
7116 },
7117};
7118
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007119static struct hda_input_mux mb5_capture_source = {
7120 .num_items = 3,
7121 .items = {
7122 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307123 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007124 { "CD", 0x4 },
7125 },
7126};
7127
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007128static struct hda_input_mux macmini3_capture_source = {
7129 .num_items = 2,
7130 .items = {
7131 { "Line", 0x2 },
7132 { "CD", 0x4 },
7133 },
7134};
7135
Takashi Iwai4953550a2009-06-30 15:28:30 +02007136static struct hda_input_mux alc883_3stack_6ch_intel = {
7137 .num_items = 4,
7138 .items = {
7139 { "Mic", 0x1 },
7140 { "Front Mic", 0x0 },
7141 { "Line", 0x2 },
7142 { "CD", 0x4 },
7143 },
7144};
7145
7146static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7147 .num_items = 2,
7148 .items = {
7149 { "Mic", 0x1 },
7150 { "Line", 0x2 },
7151 },
7152};
7153
7154static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7155 .num_items = 4,
7156 .items = {
7157 { "Mic", 0x0 },
David Henningsson150b4322010-07-29 14:46:42 +02007158 { "Int Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007159 { "Line", 0x2 },
7160 { "CD", 0x4 },
7161 },
7162};
7163
7164static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7165 .num_items = 2,
7166 .items = {
7167 { "Mic", 0x0 },
7168 { "Int Mic", 0x1 },
7169 },
7170};
7171
7172static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7173 .num_items = 3,
7174 .items = {
7175 { "Mic", 0x0 },
7176 { "Front Mic", 0x1 },
7177 { "Line", 0x4 },
7178 },
7179};
7180
7181static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7182 .num_items = 2,
7183 .items = {
7184 { "Mic", 0x0 },
7185 { "Line", 0x2 },
7186 },
7187};
7188
7189static struct hda_input_mux alc889A_mb31_capture_source = {
7190 .num_items = 2,
7191 .items = {
7192 { "Mic", 0x0 },
7193 /* Front Mic (0x01) unused */
7194 { "Line", 0x2 },
7195 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007196 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007197 },
7198};
7199
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007200static struct hda_input_mux alc889A_imac91_capture_source = {
7201 .num_items = 2,
7202 .items = {
7203 { "Mic", 0x01 },
7204 { "Line", 0x2 }, /* Not sure! */
7205 },
7206};
7207
Takashi Iwai4953550a2009-06-30 15:28:30 +02007208/*
7209 * 2ch mode
7210 */
7211static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7212 { 2, NULL }
7213};
7214
Kailang Yangdf694da2005-12-05 19:42:22 +01007215/*
Kailang Yang272a5272007-05-14 11:00:38 +02007216 * 2ch mode
7217 */
7218static struct hda_verb alc882_3ST_ch2_init[] = {
7219 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7220 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7221 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7222 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7223 { } /* end */
7224};
7225
7226/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007227 * 4ch mode
7228 */
7229static struct hda_verb alc882_3ST_ch4_init[] = {
7230 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7231 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7232 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7233 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7234 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7235 { } /* end */
7236};
7237
7238/*
Kailang Yang272a5272007-05-14 11:00:38 +02007239 * 6ch mode
7240 */
7241static struct hda_verb alc882_3ST_ch6_init[] = {
7242 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7243 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7244 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7245 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7246 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7247 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7248 { } /* end */
7249};
7250
Takashi Iwai4953550a2009-06-30 15:28:30 +02007251static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007252 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007253 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007254 { 6, alc882_3ST_ch6_init },
7255};
7256
Takashi Iwai4953550a2009-06-30 15:28:30 +02007257#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7258
Kailang Yang272a5272007-05-14 11:00:38 +02007259/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307260 * 2ch mode
7261 */
7262static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7263 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7264 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7265 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7266 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7267 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7268 { } /* end */
7269};
7270
7271/*
7272 * 4ch mode
7273 */
7274static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7275 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7276 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7277 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7278 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7279 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7280 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7281 { } /* end */
7282};
7283
7284/*
7285 * 6ch mode
7286 */
7287static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7288 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7289 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7290 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7291 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7292 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7293 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7294 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7295 { } /* end */
7296};
7297
7298static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7299 { 2, alc883_3ST_ch2_clevo_init },
7300 { 4, alc883_3ST_ch4_clevo_init },
7301 { 6, alc883_3ST_ch6_clevo_init },
7302};
7303
7304
7305/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007306 * 6ch mode
7307 */
7308static struct hda_verb alc882_sixstack_ch6_init[] = {
7309 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7310 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7311 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7312 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7313 { } /* end */
7314};
7315
7316/*
7317 * 8ch mode
7318 */
7319static struct hda_verb alc882_sixstack_ch8_init[] = {
7320 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7321 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7322 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7323 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7324 { } /* end */
7325};
7326
7327static struct hda_channel_mode alc882_sixstack_modes[2] = {
7328 { 6, alc882_sixstack_ch6_init },
7329 { 8, alc882_sixstack_ch8_init },
7330};
7331
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007332
7333/* Macbook Air 2,1 */
7334
7335static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7336 { 2, NULL },
7337};
7338
Takashi Iwai87350ad2007-08-16 18:19:38 +02007339/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007340 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007341 */
7342
7343/*
7344 * 2ch mode
7345 */
7346static struct hda_verb alc885_mbp_ch2_init[] = {
7347 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7348 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7349 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7350 { } /* end */
7351};
7352
7353/*
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007354 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007355 */
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007356static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007357 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7358 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7359 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7360 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7361 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7362 { } /* end */
7363};
7364
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007365static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007366 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007367 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007368};
7369
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007370/*
7371 * 2ch
7372 * Speakers/Woofer/HP = Front
7373 * LineIn = Input
7374 */
7375static struct hda_verb alc885_mb5_ch2_init[] = {
7376 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7377 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7378 { } /* end */
7379};
7380
7381/*
7382 * 6ch mode
7383 * Speakers/HP = Front
7384 * Woofer = LFE
7385 * LineIn = Surround
7386 */
7387static struct hda_verb alc885_mb5_ch6_init[] = {
7388 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7389 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7390 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7391 { } /* end */
7392};
7393
7394static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7395 { 2, alc885_mb5_ch2_init },
7396 { 6, alc885_mb5_ch6_init },
7397};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007398
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007399#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai4953550a2009-06-30 15:28:30 +02007400
7401/*
7402 * 2ch mode
7403 */
7404static struct hda_verb alc883_4ST_ch2_init[] = {
7405 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7406 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7407 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7408 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7409 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7410 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7411 { } /* end */
7412};
7413
7414/*
7415 * 4ch mode
7416 */
7417static struct hda_verb alc883_4ST_ch4_init[] = {
7418 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7419 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7420 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7421 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7422 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7423 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7424 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7425 { } /* end */
7426};
7427
7428/*
7429 * 6ch mode
7430 */
7431static struct hda_verb alc883_4ST_ch6_init[] = {
7432 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7433 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7434 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7435 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7436 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7437 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7438 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7439 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7440 { } /* end */
7441};
7442
7443/*
7444 * 8ch mode
7445 */
7446static struct hda_verb alc883_4ST_ch8_init[] = {
7447 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7448 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7449 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7450 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7451 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7452 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7453 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7454 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7455 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7456 { } /* end */
7457};
7458
7459static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7460 { 2, alc883_4ST_ch2_init },
7461 { 4, alc883_4ST_ch4_init },
7462 { 6, alc883_4ST_ch6_init },
7463 { 8, alc883_4ST_ch8_init },
7464};
7465
7466
7467/*
7468 * 2ch mode
7469 */
7470static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7471 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7472 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7473 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7474 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7475 { } /* end */
7476};
7477
7478/*
7479 * 4ch mode
7480 */
7481static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7482 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7483 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7484 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7485 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7486 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7487 { } /* end */
7488};
7489
7490/*
7491 * 6ch mode
7492 */
7493static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7494 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7495 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7496 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7497 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7498 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7499 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7500 { } /* end */
7501};
7502
7503static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7504 { 2, alc883_3ST_ch2_intel_init },
7505 { 4, alc883_3ST_ch4_intel_init },
7506 { 6, alc883_3ST_ch6_intel_init },
7507};
7508
7509/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007510 * 2ch mode
7511 */
7512static struct hda_verb alc889_ch2_intel_init[] = {
7513 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7514 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7515 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7516 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7517 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7518 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7519 { } /* end */
7520};
7521
7522/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007523 * 6ch mode
7524 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007525static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007526 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7527 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7528 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7529 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7530 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007531 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7532 { } /* end */
7533};
7534
7535/*
7536 * 8ch mode
7537 */
7538static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007539 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7540 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7541 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7542 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7543 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007544 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7545 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007546 { } /* end */
7547};
7548
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007549static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7550 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007551 { 6, alc889_ch6_intel_init },
7552 { 8, alc889_ch8_intel_init },
7553};
7554
7555/*
7556 * 6ch mode
7557 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007558static struct hda_verb alc883_sixstack_ch6_init[] = {
7559 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7560 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7561 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7562 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7563 { } /* end */
7564};
7565
7566/*
7567 * 8ch mode
7568 */
7569static struct hda_verb alc883_sixstack_ch8_init[] = {
7570 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7571 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7572 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7573 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7574 { } /* end */
7575};
7576
7577static struct hda_channel_mode alc883_sixstack_modes[2] = {
7578 { 6, alc883_sixstack_ch6_init },
7579 { 8, alc883_sixstack_ch8_init },
7580};
7581
7582
Linus Torvalds1da177e2005-04-16 15:20:36 -07007583/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7584 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7585 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01007586static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007587 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007588 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007589 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007590 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007591 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7592 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007593 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7594 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007595 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007596 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7598 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7599 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7600 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7601 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7602 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007603 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7605 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007606 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007607 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608 { } /* end */
7609};
7610
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007611/* Macbook Air 2,1 same control for HP and internal Speaker */
7612
7613static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7614 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7615 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7616 { }
7617};
7618
7619
Takashi Iwai87350ad2007-08-16 18:19:38 +02007620static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007621 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7622 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7623 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7624 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7625 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007626 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7627 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007628 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7629 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007630 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007631 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7632 { } /* end */
7633};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007634
7635static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007636 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7637 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7638 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7639 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7640 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7641 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307642 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7643 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307644 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7645 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7647 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7648 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7649 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7650 { } /* end */
7651};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007652
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007653static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7654 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7655 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7656 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7657 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7658 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7659 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7660 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7661 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7662 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7663 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7664 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7665 { } /* end */
7666};
7667
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007668static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007669 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7670 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007671 { } /* end */
7672};
7673
7674
Kailang Yangbdd148a2007-05-08 15:19:08 +02007675static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7676 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7677 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7678 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7679 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7680 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7681 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7682 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7683 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7684 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007685 { } /* end */
7686};
7687
Kailang Yang272a5272007-05-14 11:00:38 +02007688static struct snd_kcontrol_new alc882_targa_mixer[] = {
7689 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7690 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7691 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7692 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7693 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7694 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7695 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7696 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7697 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007698 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007699 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7700 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007701 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007702 { } /* end */
7703};
7704
7705/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7706 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7707 */
7708static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7709 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7710 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7711 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7712 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7713 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7714 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7715 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7716 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7717 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7718 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7719 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7720 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007721 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007722 { } /* end */
7723};
7724
Takashi Iwai914759b2007-09-06 14:52:04 +02007725static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7726 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7727 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7728 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7729 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7730 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7731 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7732 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7733 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7734 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7735 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007736 { } /* end */
7737};
7738
Kailang Yangdf694da2005-12-05 19:42:22 +01007739static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7740 {
7741 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7742 .name = "Channel Mode",
7743 .info = alc_ch_mode_info,
7744 .get = alc_ch_mode_get,
7745 .put = alc_ch_mode_put,
7746 },
7747 { } /* end */
7748};
7749
Takashi Iwai4953550a2009-06-30 15:28:30 +02007750static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007752 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7753 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007755 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7756 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007757 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007758 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7759 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007760 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007761 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7762 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007763
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007764 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007765 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007766 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007767 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007768 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007769 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007770 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007771 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007772 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007773 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007774 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007776 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007777 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007778 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007780 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007781 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007782 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7783 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007784 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007785 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7786 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007787 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007788 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7789 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7790 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7791 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7792 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007794 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795
7796 /* FIXME: use matrix-type input source selection */
7797 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007798 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007799 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007801 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007802 /* ADC2: mute amp left and right */
7803 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007804 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007805 /* ADC3: mute amp left and right */
7806 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007807 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808
7809 { }
7810};
7811
Takashi Iwai4953550a2009-06-30 15:28:30 +02007812static struct hda_verb alc882_adc1_init_verbs[] = {
7813 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7814 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7815 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7816 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7817 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7818 /* ADC1: mute amp left and right */
7819 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7820 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7821 { }
7822};
7823
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007824static struct hda_verb alc882_eapd_verbs[] = {
7825 /* change to EAPD mode */
7826 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007827 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007828 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007829};
7830
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007831static struct hda_verb alc889_eapd_verbs[] = {
7832 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7833 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7834 { }
7835};
7836
Wu Fengguang6732bd02009-07-30 09:19:14 +02007837static struct hda_verb alc_hp15_unsol_verbs[] = {
7838 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7839 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7840 {}
7841};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007842
7843static struct hda_verb alc885_init_verbs[] = {
7844 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01007845 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7846 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007847 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007848 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7849 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007850 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007851 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7852 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007853 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007854 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7855 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007856
7857 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007858 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007859 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7860 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7861 /* Front Pin: output 0 (0x0c) */
7862 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7863 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7864 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7865 /* Rear Pin: output 1 (0x0d) */
7866 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7867 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7868 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7869 /* CLFE Pin: output 2 (0x0e) */
7870 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7871 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7872 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7873 /* Side Pin: output 3 (0x0f) */
7874 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7875 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7876 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7877 /* Mic (rear) pin: input vref at 80% */
7878 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7879 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7880 /* Front Mic pin: input vref at 80% */
7881 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7882 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7883 /* Line In pin: input */
7884 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7885 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7886
7887 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7888 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01007889 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007890 /* Input mixer2 */
7891 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007892 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01007893 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007894 /* ADC2: mute amp left and right */
7895 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7896 /* ADC3: mute amp left and right */
7897 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7898
7899 { }
7900};
7901
7902static struct hda_verb alc885_init_input_verbs[] = {
7903 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7904 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7905 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7906 { }
7907};
7908
7909
7910/* Unmute Selector 24h and set the default input to front mic */
7911static struct hda_verb alc889_init_input_verbs[] = {
7912 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7913 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7914 { }
7915};
7916
7917
Takashi Iwai4953550a2009-06-30 15:28:30 +02007918#define alc883_init_verbs alc882_base_init_verbs
7919
Tobin Davis9102cd12006-12-15 10:02:12 +01007920/* Mac Pro test */
7921static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7922 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7923 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7924 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7925 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7926 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007927 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007928 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7929 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007930 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007931 { } /* end */
7932};
7933
7934static struct hda_verb alc882_macpro_init_verbs[] = {
7935 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7936 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7937 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7938 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7939 /* Front Pin: output 0 (0x0c) */
7940 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7941 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7942 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7943 /* Front Mic pin: input vref at 80% */
7944 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7945 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7946 /* Speaker: output */
7947 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7948 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7949 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7950 /* Headphone output (output 0 - 0x0c) */
7951 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7952 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7953 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7954
7955 /* FIXME: use matrix-type input source selection */
7956 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7957 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7958 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7959 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7960 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7961 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7962 /* Input mixer2 */
7963 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7964 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7965 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7966 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7967 /* Input mixer3 */
7968 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7969 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7970 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7971 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7972 /* ADC1: mute amp left and right */
7973 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7974 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7975 /* ADC2: mute amp left and right */
7976 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7977 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7978 /* ADC3: mute amp left and right */
7979 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7980 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7981
7982 { }
7983};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007984
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007985/* Macbook 5,1 */
7986static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007987 /* DACs */
7988 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7989 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7990 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7991 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007992 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007993 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7994 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7995 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007996 /* Surround mixer */
7997 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7998 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7999 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8000 /* LFE mixer */
8001 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8002 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8003 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8004 /* HP mixer */
8005 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8006 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8007 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8008 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008009 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8010 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008011 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8012 /* LFE Pin (0x0e) */
8013 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8014 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8015 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8016 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008017 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8018 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008019 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308020 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008021 /* Front Mic pin: input vref at 80% */
8022 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8023 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8024 /* Line In pin */
8025 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8026 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8027
Alex Murrayb8f171e2010-06-14 12:08:43 +09308028 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8029 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8030 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008031 { }
8032};
8033
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008034/* Macmini 3,1 */
8035static struct hda_verb alc885_macmini3_init_verbs[] = {
8036 /* DACs */
8037 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8038 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8039 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8040 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8041 /* Front mixer */
8042 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8043 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8044 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8045 /* Surround mixer */
8046 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8047 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8048 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8049 /* LFE mixer */
8050 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8051 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8052 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8053 /* HP mixer */
8054 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8055 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8056 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8057 /* Front Pin (0x0c) */
8058 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8059 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8060 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8061 /* LFE Pin (0x0e) */
8062 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8063 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8064 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8065 /* HP Pin (0x0f) */
8066 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8067 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8068 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8069 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8070 /* Line In pin */
8071 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8072 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8073
8074 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8075 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8076 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8077 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8078 { }
8079};
8080
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008081
8082static struct hda_verb alc885_mba21_init_verbs[] = {
8083 /*Internal and HP Speaker Mixer*/
8084 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8085 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8086 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8087 /*Internal Speaker Pin (0x0c)*/
8088 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8089 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8090 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8091 /* HP Pin: output 0 (0x0e) */
8092 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8093 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8094 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8095 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8096 /* Line in (is hp when jack connected)*/
8097 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8098 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8099
8100 { }
8101 };
8102
8103
Takashi Iwai87350ad2007-08-16 18:19:38 +02008104/* Macbook Pro rev3 */
8105static struct hda_verb alc885_mbp3_init_verbs[] = {
8106 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8107 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8108 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8109 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8110 /* Rear mixer */
8111 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8112 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8113 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008114 /* HP mixer */
8115 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8116 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8117 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008118 /* Front Pin: output 0 (0x0c) */
8119 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8120 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8121 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008122 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008123 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008124 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8125 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008126 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8127 /* Mic (rear) pin: input vref at 80% */
8128 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8129 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8130 /* Front Mic pin: input vref at 80% */
8131 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8132 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8133 /* Line In pin: use output 1 when in LineOut mode */
8134 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8135 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8136 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8137
8138 /* FIXME: use matrix-type input source selection */
8139 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8140 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8141 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8142 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8143 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8144 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8145 /* Input mixer2 */
8146 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8147 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8148 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8149 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8150 /* Input mixer3 */
8151 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8152 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8153 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8154 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8155 /* ADC1: mute amp left and right */
8156 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8157 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8158 /* ADC2: mute amp left and right */
8159 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8160 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8161 /* ADC3: mute amp left and right */
8162 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8163 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8164
8165 { }
8166};
8167
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008168/* iMac 9,1 */
8169static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008170 /* Internal Speaker Pin (0x0c) */
8171 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8172 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8173 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8174 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8175 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8176 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8177 /* HP Pin: Rear */
8178 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8179 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8180 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8181 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8182 /* Line in Rear */
8183 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8185 /* Front Mic pin: input vref at 80% */
8186 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8187 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008188 /* Rear mixer */
8189 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8190 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8191 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008192 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8193 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8194 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8195 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8196 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008197 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8198 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8199 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8200 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008201 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008202 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8203 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8204 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8205 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008206 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008207 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8208 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8209 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8210 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008211 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008212 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8213 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008214 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008215 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8216 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008217 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008218 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8219 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008220 { }
8221};
8222
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008223/* iMac 24 mixer. */
8224static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8225 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8226 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8227 { } /* end */
8228};
8229
8230/* iMac 24 init verbs. */
8231static struct hda_verb alc885_imac24_init_verbs[] = {
8232 /* Internal speakers: output 0 (0x0c) */
8233 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8234 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8235 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8236 /* Internal speakers: output 0 (0x0c) */
8237 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8238 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8239 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8240 /* Headphone: output 0 (0x0c) */
8241 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8242 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8243 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8244 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8245 /* Front Mic: input vref at 80% */
8246 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8247 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8248 { }
8249};
8250
8251/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008252static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008253{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008254 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008255
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008256 spec->autocfg.hp_pins[0] = 0x14;
8257 spec->autocfg.speaker_pins[0] = 0x18;
8258 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008259}
8260
Takashi Iwai9d54f082010-02-22 08:34:40 +01008261#define alc885_mb5_setup alc885_imac24_setup
8262#define alc885_macmini3_setup alc885_imac24_setup
8263
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008264/* Macbook Air 2,1 */
8265static void alc885_mba21_setup(struct hda_codec *codec)
8266{
8267 struct alc_spec *spec = codec->spec;
8268
8269 spec->autocfg.hp_pins[0] = 0x14;
8270 spec->autocfg.speaker_pins[0] = 0x18;
8271}
8272
8273
8274
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008275static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008276{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008277 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008278
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008279 spec->autocfg.hp_pins[0] = 0x15;
8280 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008281}
8282
Takashi Iwai9d54f082010-02-22 08:34:40 +01008283static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308284{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008285 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308286
Takashi Iwai9d54f082010-02-22 08:34:40 +01008287 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008288 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008289 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008290}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008291
Kailang Yang272a5272007-05-14 11:00:38 +02008292static struct hda_verb alc882_targa_verbs[] = {
8293 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8294 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8295
8296 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8297 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008298
Kailang Yang272a5272007-05-14 11:00:38 +02008299 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8300 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8301 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8302
8303 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008304 { } /* end */
8305};
8306
8307/* toggle speaker-output according to the hp-jack state */
8308static void alc882_targa_automute(struct hda_codec *codec)
8309{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008310 struct alc_spec *spec = codec->spec;
8311 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008312 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008313 spec->jack_present ? 1 : 3);
8314}
8315
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008316static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008317{
8318 struct alc_spec *spec = codec->spec;
8319
8320 spec->autocfg.hp_pins[0] = 0x14;
8321 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008322}
8323
8324static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8325{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008326 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008327 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008328}
8329
8330static struct hda_verb alc882_asus_a7j_verbs[] = {
8331 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8332 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8333
8334 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8335 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8336 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008337
Kailang Yang272a5272007-05-14 11:00:38 +02008338 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8339 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8340 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8341
8342 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8343 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8344 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8345 { } /* end */
8346};
8347
Takashi Iwai914759b2007-09-06 14:52:04 +02008348static struct hda_verb alc882_asus_a7m_verbs[] = {
8349 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8351
8352 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8353 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8354 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008355
Takashi Iwai914759b2007-09-06 14:52:04 +02008356 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8357 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8358 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8359
8360 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8361 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8362 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8363 { } /* end */
8364};
8365
Tobin Davis9102cd12006-12-15 10:02:12 +01008366static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8367{
8368 unsigned int gpiostate, gpiomask, gpiodir;
8369
8370 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8371 AC_VERB_GET_GPIO_DATA, 0);
8372
8373 if (!muted)
8374 gpiostate |= (1 << pin);
8375 else
8376 gpiostate &= ~(1 << pin);
8377
8378 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8379 AC_VERB_GET_GPIO_MASK, 0);
8380 gpiomask |= (1 << pin);
8381
8382 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8383 AC_VERB_GET_GPIO_DIRECTION, 0);
8384 gpiodir |= (1 << pin);
8385
8386
8387 snd_hda_codec_write(codec, codec->afg, 0,
8388 AC_VERB_SET_GPIO_MASK, gpiomask);
8389 snd_hda_codec_write(codec, codec->afg, 0,
8390 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8391
8392 msleep(1);
8393
8394 snd_hda_codec_write(codec, codec->afg, 0,
8395 AC_VERB_SET_GPIO_DATA, gpiostate);
8396}
8397
Takashi Iwai7debbe52007-08-16 15:01:03 +02008398/* set up GPIO at initialization */
8399static void alc885_macpro_init_hook(struct hda_codec *codec)
8400{
8401 alc882_gpio_mute(codec, 0, 0);
8402 alc882_gpio_mute(codec, 1, 0);
8403}
8404
8405/* set up GPIO and update auto-muting at initialization */
8406static void alc885_imac24_init_hook(struct hda_codec *codec)
8407{
8408 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008409 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008410}
8411
Kailang Yangdf694da2005-12-05 19:42:22 +01008412/*
8413 * generic initialization of ADC, input mixers and output mixers
8414 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008415static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008416 /*
8417 * Unmute ADC0-2 and set the default input to mic-in
8418 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008419 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8420 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8421 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8422 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8423
Kailang Yangdf694da2005-12-05 19:42:22 +01008424 /*
8425 * Set up output mixers (0x0c - 0x0f)
8426 */
8427 /* set vol=0 to output mixers */
8428 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8429 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8430 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8431 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8432 /* set up input amps for analog loopback */
8433 /* Amp Indices: DAC = 0, mixer = 1 */
8434 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8435 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8436 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8437 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8438 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8439 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8440 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8441 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8442 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8443 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8444
8445 /* FIXME: use matrix-type input source selection */
8446 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008447 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008448 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008449 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008450 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008451 { }
8452};
8453
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008454/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8455static struct hda_verb alc889A_mb31_ch2_init[] = {
8456 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8457 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8458 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8459 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8460 { } /* end */
8461};
8462
8463/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8464static struct hda_verb alc889A_mb31_ch4_init[] = {
8465 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8466 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8467 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8468 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8469 { } /* end */
8470};
8471
8472/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8473static struct hda_verb alc889A_mb31_ch5_init[] = {
8474 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8475 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8476 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8477 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8478 { } /* end */
8479};
8480
8481/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8482static struct hda_verb alc889A_mb31_ch6_init[] = {
8483 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8484 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8485 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8486 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8487 { } /* end */
8488};
8489
8490static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8491 { 2, alc889A_mb31_ch2_init },
8492 { 4, alc889A_mb31_ch4_init },
8493 { 5, alc889A_mb31_ch5_init },
8494 { 6, alc889A_mb31_ch6_init },
8495};
8496
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008497static struct hda_verb alc883_medion_eapd_verbs[] = {
8498 /* eanable EAPD on medion laptop */
8499 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8500 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8501 { }
8502};
8503
Takashi Iwai4953550a2009-06-30 15:28:30 +02008504#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008505
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008506static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8507 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8508 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8509 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8510 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8511 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8512 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8513 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8515 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8516 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8517 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8518 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8519 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008520 { } /* end */
8521};
8522
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008523static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008524 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8525 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8526 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8527 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8528 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8529 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8530 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8531 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8532 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8533 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008534 { } /* end */
8535};
8536
Jiang zhefb97dc62008-03-06 11:07:11 +01008537static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8538 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8539 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8540 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8541 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8542 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8543 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8544 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8545 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8546 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8547 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008548 { } /* end */
8549};
8550
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008551static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8552 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8553 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8554 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8555 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8556 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8557 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8558 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8559 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008560 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008561 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8562 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008563 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008564 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008565 { } /* end */
8566};
8567
8568static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8569 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8570 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8571 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8572 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8573 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8574 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8575 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8576 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8577 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8578 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8579 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8580 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8581 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8582 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008583 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008584 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8585 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008586 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008587 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008588 { } /* end */
8589};
8590
Jiang zhe17bba1b2008-06-04 12:11:07 +02008591static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8592 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8593 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8594 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8595 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8596 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8597 HDA_OUTPUT),
8598 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8599 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8600 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8601 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8602 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8603 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8604 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8605 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8606 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8607 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8608 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8609 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8610 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8611 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008612 { } /* end */
8613};
8614
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008615static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8616 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8617 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8618 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8619 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8620 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8621 HDA_OUTPUT),
8622 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8623 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8624 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8625 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8626 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8627 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8628 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8629 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8630 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8631 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8632 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8633 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8634 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8635 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8636 { } /* end */
8637};
8638
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008639static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008640 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008641 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008642 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008643 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008644 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8645 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008646 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8647 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008648 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8649 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8650 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8651 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8652 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8653 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008654 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008655 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8656 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008657 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008658 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008659 { } /* end */
8660};
8661
Sasha Alexandrc2592492009-06-16 14:52:54 -04008662static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008663 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008664 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008665 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008666 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008667 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8668 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8669 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8670 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8671 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8672 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8673 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8674 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8675 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8676 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8677 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008678 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008679 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008680 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008681};
Kailang Yangccc656c2006-10-17 12:32:26 +02008682
Sasha Alexandrc2592492009-06-16 14:52:54 -04008683static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008684 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008685 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008686 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008687 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008688 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8689 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8690 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008691 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008692 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008693 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8694 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8695 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008696 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008697};
Kailang Yangccc656c2006-10-17 12:32:26 +02008698
Takashi Iwaib99dba32009-09-17 18:23:00 +02008699static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8700 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8701 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8702 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8703 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8704 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8705 { } /* end */
8706};
8707
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008708static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8709 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8710 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008711 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8712 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008713 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8714 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8715 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8716 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008717 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008718};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008719
Kailang Yang272a5272007-05-14 11:00:38 +02008720static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8721 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8722 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8723 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8724 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8725 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8726 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8727 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson150b4322010-07-29 14:46:42 +02008728 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8729 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008730 { } /* end */
8731};
8732
8733static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8734 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8735 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8736 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8737 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8738 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8739 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8740 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8741 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8742 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008743 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008744};
Kailang Yang272a5272007-05-14 11:00:38 +02008745
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02008746static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
8747 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8748 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8749 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8750 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
8751 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
8752 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
8753 { } /* end */
8754};
8755
8756static struct hda_verb alc883_medion_wim2160_verbs[] = {
8757 /* Unmute front mixer */
8758 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8759 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8760
8761 /* Set speaker pin to front mixer */
8762 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8763
8764 /* Init headphone pin */
8765 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8766 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8767 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8768 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8769
8770 { } /* end */
8771};
8772
8773/* toggle speaker-output according to the hp-jack state */
8774static void alc883_medion_wim2160_setup(struct hda_codec *codec)
8775{
8776 struct alc_spec *spec = codec->spec;
8777
8778 spec->autocfg.hp_pins[0] = 0x1a;
8779 spec->autocfg.speaker_pins[0] = 0x15;
8780}
8781
Tobin Davis2880a862007-08-07 11:50:26 +02008782static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008783 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8784 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008785 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008786 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8787 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008788 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8789 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8790 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008791 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008792};
Tobin Davis2880a862007-08-07 11:50:26 +02008793
Tony Vroond2fd4b02009-06-21 00:40:10 +01008794static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8795 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008796 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008797 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8798 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008799 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8800 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8801 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8802 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8803 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8804 { } /* end */
8805};
8806
Kailang Yange2757d52008-08-26 13:17:46 +02008807static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8808 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8809 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8810 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8811 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8812 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8813 0x0d, 1, 0x0, HDA_OUTPUT),
8814 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8815 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8816 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8817 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8818 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008819 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8820 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8821 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8822 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8823 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8824 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8825 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8826 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8827 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8828 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008829 { } /* end */
8830};
8831
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008832static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8833 /* Output mixers */
8834 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8835 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8836 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8837 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8838 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8839 HDA_OUTPUT),
8840 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8841 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8842 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8843 /* Output switches */
8844 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8845 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8846 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8847 /* Boost mixers */
8848 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8849 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8850 /* Input mixers */
8851 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8852 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8853 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8854 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8855 { } /* end */
8856};
8857
Guido Günther3e1647c2009-06-05 00:47:26 +02008858static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8859 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8860 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8861 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8862 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8863 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8864 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8865 { } /* end */
8866};
8867
Kailang Yange2757d52008-08-26 13:17:46 +02008868static struct hda_bind_ctls alc883_bind_cap_vol = {
8869 .ops = &snd_hda_bind_vol,
8870 .values = {
8871 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8872 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8873 0
8874 },
8875};
8876
8877static struct hda_bind_ctls alc883_bind_cap_switch = {
8878 .ops = &snd_hda_bind_sw,
8879 .values = {
8880 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8881 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8882 0
8883 },
8884};
8885
8886static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8887 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8888 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8889 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8890 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8891 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8892 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8893 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8894 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008895 { } /* end */
8896};
8897
8898static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008899 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8900 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8901 {
8902 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8903 /* .name = "Capture Source", */
8904 .name = "Input Source",
8905 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008906 .info = alc_mux_enum_info,
8907 .get = alc_mux_enum_get,
8908 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008909 },
8910 { } /* end */
8911};
8912
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008913static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8914 {
8915 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8916 .name = "Channel Mode",
8917 .info = alc_ch_mode_info,
8918 .get = alc_ch_mode_get,
8919 .put = alc_ch_mode_put,
8920 },
8921 { } /* end */
8922};
8923
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008924/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008925static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008926{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008927 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008928
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008929 spec->autocfg.hp_pins[0] = 0x15;
8930 spec->autocfg.speaker_pins[0] = 0x14;
8931 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008932}
8933
8934/* auto-toggle front mic */
8935/*
8936static void alc883_mitac_mic_automute(struct hda_codec *codec)
8937{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008938 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008939
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008940 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8941}
8942*/
8943
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008944static struct hda_verb alc883_mitac_verbs[] = {
8945 /* HP */
8946 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8947 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8948 /* Subwoofer */
8949 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8950 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8951
8952 /* enable unsolicited event */
8953 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8954 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8955
8956 { } /* end */
8957};
8958
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308959static struct hda_verb alc883_clevo_m540r_verbs[] = {
8960 /* HP */
8961 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8962 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8963 /* Int speaker */
8964 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8965
8966 /* enable unsolicited event */
8967 /*
8968 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8969 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8970 */
8971
8972 { } /* end */
8973};
8974
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008975static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008976 /* HP */
8977 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8978 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8979 /* Int speaker */
8980 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8981 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8982
8983 /* enable unsolicited event */
8984 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008985 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008986
8987 { } /* end */
8988};
8989
Jiang zhefb97dc62008-03-06 11:07:11 +01008990static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8991 /* HP */
8992 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8993 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8994 /* Subwoofer */
8995 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8996 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8997
8998 /* enable unsolicited event */
8999 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9000
9001 { } /* end */
9002};
9003
Sasha Alexandrc2592492009-06-16 14:52:54 -04009004static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009005 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9006 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9007
9008 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9009 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009010
David Heidelberger64a8be72009-06-08 16:15:18 +02009011/* Connect Line-Out side jack (SPDIF) to Side */
9012 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9013 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9014 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9015/* Connect Mic jack to CLFE */
9016 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9017 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9018 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9019/* Connect Line-in jack to Surround */
9020 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9021 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9022 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9023/* Connect HP out jack to Front */
9024 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9025 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9026 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009027
9028 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009029
9030 { } /* end */
9031};
9032
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009033static struct hda_verb alc883_lenovo_101e_verbs[] = {
9034 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9035 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9036 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9037 { } /* end */
9038};
9039
Kailang Yang272a5272007-05-14 11:00:38 +02009040static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9041 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9042 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9043 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9044 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9045 { } /* end */
9046};
9047
9048static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9049 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9050 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9051 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9052 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9053 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9054 { } /* end */
9055};
9056
Kailang Yang189609a2007-08-20 11:31:23 +02009057static struct hda_verb alc883_haier_w66_verbs[] = {
9058 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9059 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9060
9061 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9062
9063 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9064 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9065 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9066 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9067 { } /* end */
9068};
9069
Kailang Yange2757d52008-08-26 13:17:46 +02009070static struct hda_verb alc888_lenovo_sky_verbs[] = {
9071 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9072 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9073 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9074 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9075 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9076 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9077 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9078 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9079 { } /* end */
9080};
9081
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009082static struct hda_verb alc888_6st_dell_verbs[] = {
9083 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9084 { }
9085};
9086
Guido Günther3e1647c2009-06-05 00:47:26 +02009087static struct hda_verb alc883_vaiott_verbs[] = {
9088 /* HP */
9089 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9090 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9091
9092 /* enable unsolicited event */
9093 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9094
9095 { } /* end */
9096};
9097
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009098static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009099{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009100 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009101
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009102 spec->autocfg.hp_pins[0] = 0x1b;
9103 spec->autocfg.speaker_pins[0] = 0x14;
9104 spec->autocfg.speaker_pins[1] = 0x16;
9105 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009106}
9107
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009108static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009109 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009110 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9111 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009112 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009113 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009114};
9115
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009116/*
9117 * 2ch mode
9118 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009119static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009120 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9121 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9122 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9123 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009124 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009125};
9126
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009127/*
9128 * 4ch mode
9129 */
9130static struct hda_verb alc888_3st_hp_4ch_init[] = {
9131 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9132 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9133 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9134 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9135 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9136 { } /* end */
9137};
9138
9139/*
9140 * 6ch mode
9141 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009142static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009143 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9144 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009145 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009146 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9147 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009148 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9149 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009150};
9151
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009152static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009153 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009154 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009155 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009156};
9157
Kailang Yang272a5272007-05-14 11:00:38 +02009158/* toggle front-jack and RCA according to the hp-jack state */
9159static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9160{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009161 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009162
Takashi Iwai47fd8302007-08-10 17:11:07 +02009163 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9164 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9165 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9166 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009167}
9168
9169/* toggle RCA according to the front-jack state */
9170static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9171{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009172 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009173
Takashi Iwai47fd8302007-08-10 17:11:07 +02009174 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9175 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009176}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009177
Kailang Yang272a5272007-05-14 11:00:38 +02009178static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9179 unsigned int res)
9180{
9181 if ((res >> 26) == ALC880_HP_EVENT)
9182 alc888_lenovo_ms7195_front_automute(codec);
9183 if ((res >> 26) == ALC880_FRONT_EVENT)
9184 alc888_lenovo_ms7195_rca_automute(codec);
9185}
9186
9187static struct hda_verb alc883_medion_md2_verbs[] = {
9188 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9189 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9190
9191 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9192
9193 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9194 { } /* end */
9195};
9196
9197/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009198static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009199{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009200 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009201
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009202 spec->autocfg.hp_pins[0] = 0x14;
9203 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009204}
9205
Kailang Yangccc656c2006-10-17 12:32:26 +02009206/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009207#define alc883_targa_init_hook alc882_targa_init_hook
9208#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009209
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009210static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
9211{
9212 unsigned int present;
9213
Takashi Iwaid56757a2009-11-18 08:00:14 +01009214 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009215 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
9216 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9217}
9218
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009219static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009220{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009221 struct alc_spec *spec = codec->spec;
9222
9223 spec->autocfg.hp_pins[0] = 0x15;
9224 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009225}
9226
9227static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9228{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009229 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009230 alc883_clevo_m720_mic_automute(codec);
9231}
9232
9233static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009234 unsigned int res)
9235{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009236 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009237 case ALC880_MIC_EVENT:
9238 alc883_clevo_m720_mic_automute(codec);
9239 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009240 default:
9241 alc_automute_amp_unsol_event(codec, res);
9242 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009243 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009244}
9245
Jiang zhefb97dc62008-03-06 11:07:11 +01009246/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009247static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009248{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009249 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009250
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009251 spec->autocfg.hp_pins[0] = 0x14;
9252 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009253}
9254
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009255static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009256{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009257 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009258
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009259 spec->autocfg.hp_pins[0] = 0x1b;
9260 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009261}
9262
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009263static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9264{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009265 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009266
Takashi Iwai47fd8302007-08-10 17:11:07 +02009267 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9268 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009269}
9270
9271static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9272{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009273 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009274
Takashi Iwai47fd8302007-08-10 17:11:07 +02009275 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9276 HDA_AMP_MUTE, bits);
9277 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9278 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009279}
9280
9281static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9282 unsigned int res)
9283{
9284 if ((res >> 26) == ALC880_HP_EVENT)
9285 alc883_lenovo_101e_all_automute(codec);
9286 if ((res >> 26) == ALC880_FRONT_EVENT)
9287 alc883_lenovo_101e_ispeaker_automute(codec);
9288}
9289
Takashi Iwai676a9b52007-08-16 15:23:35 +02009290/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009291static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009292{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009293 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009294
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009295 spec->autocfg.hp_pins[0] = 0x14;
9296 spec->autocfg.speaker_pins[0] = 0x15;
9297 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009298}
9299
Kailang Yangd1a991a2007-08-15 16:21:59 +02009300static struct hda_verb alc883_acer_eapd_verbs[] = {
9301 /* HP Pin: output 0 (0x0c) */
9302 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9303 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9304 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9305 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009306 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9307 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009308 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009309 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9310 /* eanable EAPD on medion laptop */
9311 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9312 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009313 /* enable unsolicited event */
9314 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009315 { }
9316};
9317
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009318static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
9319 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9320 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9321 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9322 { } /* end */
9323};
9324
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009325static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009326{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009327 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009328
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009329 spec->autocfg.hp_pins[0] = 0x1b;
9330 spec->autocfg.speaker_pins[0] = 0x14;
9331 spec->autocfg.speaker_pins[1] = 0x15;
9332 spec->autocfg.speaker_pins[2] = 0x16;
9333 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009334}
9335
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009336static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009337{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009338 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009339
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009340 spec->autocfg.hp_pins[0] = 0x1b;
9341 spec->autocfg.speaker_pins[0] = 0x14;
9342 spec->autocfg.speaker_pins[1] = 0x15;
9343 spec->autocfg.speaker_pins[2] = 0x16;
9344 spec->autocfg.speaker_pins[3] = 0x17;
9345 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009346}
9347
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009348static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009349{
9350 struct alc_spec *spec = codec->spec;
9351
9352 spec->autocfg.hp_pins[0] = 0x15;
9353 spec->autocfg.speaker_pins[0] = 0x14;
9354 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009355}
9356
Kailang Yange2757d52008-08-26 13:17:46 +02009357static struct hda_verb alc888_asus_m90v_verbs[] = {
9358 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9359 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9360 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9361 /* enable unsolicited event */
9362 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9363 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9364 { } /* end */
9365};
9366
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009367static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009368{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009369 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009370
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009371 spec->autocfg.hp_pins[0] = 0x1b;
9372 spec->autocfg.speaker_pins[0] = 0x14;
9373 spec->autocfg.speaker_pins[1] = 0x15;
9374 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009375 spec->ext_mic.pin = 0x18;
9376 spec->int_mic.pin = 0x19;
9377 spec->ext_mic.mux_idx = 0;
9378 spec->int_mic.mux_idx = 1;
9379 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009380}
9381
9382static struct hda_verb alc888_asus_eee1601_verbs[] = {
9383 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9384 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9386 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9387 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9388 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9389 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9390 /* enable unsolicited event */
9391 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9392 { } /* end */
9393};
9394
Kailang Yange2757d52008-08-26 13:17:46 +02009395static void alc883_eee1601_inithook(struct hda_codec *codec)
9396{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009397 struct alc_spec *spec = codec->spec;
9398
9399 spec->autocfg.hp_pins[0] = 0x14;
9400 spec->autocfg.speaker_pins[0] = 0x1b;
9401 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009402}
9403
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009404static struct hda_verb alc889A_mb31_verbs[] = {
9405 /* Init rear pin (used as headphone output) */
9406 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9407 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9408 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9409 /* Init line pin (used as output in 4ch and 6ch mode) */
9410 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9411 /* Init line 2 pin (used as headphone out by default) */
9412 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9413 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9414 { } /* end */
9415};
9416
9417/* Mute speakers according to the headphone jack state */
9418static void alc889A_mb31_automute(struct hda_codec *codec)
9419{
9420 unsigned int present;
9421
9422 /* Mute only in 2ch or 4ch mode */
9423 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9424 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009425 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009426 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9427 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9428 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9429 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9430 }
9431}
9432
9433static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9434{
9435 if ((res >> 26) == ALC880_HP_EVENT)
9436 alc889A_mb31_automute(codec);
9437}
9438
Takashi Iwai4953550a2009-06-30 15:28:30 +02009439
Takashi Iwaicb53c622007-08-10 17:21:45 +02009440#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02009441#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009442#endif
9443
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009444/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009445#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9446#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9447#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9448#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9449
9450static hda_nid_t alc883_slave_dig_outs[] = {
9451 ALC1200_DIGOUT_NID, 0,
9452};
9453
9454static hda_nid_t alc1200_slave_dig_outs[] = {
9455 ALC883_DIGOUT_NID, 0,
9456};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009457
9458/*
9459 * configuration and preset
9460 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009461static const char *alc882_models[ALC882_MODEL_LAST] = {
9462 [ALC882_3ST_DIG] = "3stack-dig",
9463 [ALC882_6ST_DIG] = "6stack-dig",
9464 [ALC882_ARIMA] = "arima",
9465 [ALC882_W2JC] = "w2jc",
9466 [ALC882_TARGA] = "targa",
9467 [ALC882_ASUS_A7J] = "asus-a7j",
9468 [ALC882_ASUS_A7M] = "asus-a7m",
9469 [ALC885_MACPRO] = "macpro",
9470 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009471 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009472 [ALC885_MBA21] = "mba21",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009473 [ALC885_MBP3] = "mbp3",
9474 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009475 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009476 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009477 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9478 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009479 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009480 [ALC883_TARGA_DIG] = "targa-dig",
9481 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009482 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009483 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009484 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009485 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009486 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009487 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009488 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009489 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009490 [ALC883_MEDION_MD2] = "medion-md2",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009491 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009492 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009493 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009494 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9495 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009496 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009497 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009498 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009499 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009500 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309501 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009502 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009503 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009504 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009505 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009506 [ALC889A_INTEL] = "intel-alc889a",
9507 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009508 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009509 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009510 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009511 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009512};
9513
Takashi Iwai4953550a2009-06-30 15:28:30 +02009514static struct snd_pci_quirk alc882_cfg_tbl[] = {
9515 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9516
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009517 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009518 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009519 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009520 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9521 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009522 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009523 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9524 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009525 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009526 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009527 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9528 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009529 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9530 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009531 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9532 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009533 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009534 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009535 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009536 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009537 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9538 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009539 /* default Acer -- disabled as it causes more problems.
9540 * model=auto should work fine now
9541 */
9542 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009543
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009544 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009545
Tobin Davisfebe3372007-06-12 11:27:46 +02009546 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009547 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9548 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009549 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009550 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009551 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009552
9553 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9554 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9555 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009556 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009557 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9558 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9559 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009560 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009561 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009562 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009563 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009564
9565 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009566 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009567 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009568 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009569 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9570 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009571 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009572 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009573 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9574
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009575 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9576 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9577 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009578 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009579 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009580 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009581 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009582 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009583 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9584 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9585 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9586 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9587 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9588 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009589 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009590 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9591 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9592 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009593 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009594 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009595 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9596 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009597 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009598 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009599 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009600 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009601 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009602 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009603 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009604 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009605 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009606
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009607 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009608 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009609 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9610 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309611 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009612 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009613 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009614 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009615 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009616 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009617 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009618 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009619 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009620 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009621 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009622 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9623 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009624 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009625 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009626 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009627 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009628 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009629
Jiang zhe17bba1b2008-06-04 12:11:07 +02009630 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9631 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009632 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009633 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9634 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9635 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009636 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009637
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009638 {}
9639};
9640
Takashi Iwai4953550a2009-06-30 15:28:30 +02009641/* codec SSID table for Intel Mac */
9642static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9643 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9644 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9645 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9646 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9647 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9648 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9649 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009650 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009651 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009652 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009653 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009654 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9655 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9656 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009657 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009658 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009659 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009660 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9661 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +02009662 */
9663 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009664 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009665 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009666 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009667};
9668
Takashi Iwai4953550a2009-06-30 15:28:30 +02009669static struct alc_config_preset alc882_presets[] = {
9670 [ALC882_3ST_DIG] = {
9671 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009672 .init_verbs = { alc882_base_init_verbs,
9673 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009674 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9675 .dac_nids = alc882_dac_nids,
9676 .dig_out_nid = ALC882_DIGOUT_NID,
9677 .dig_in_nid = ALC882_DIGIN_NID,
9678 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9679 .channel_mode = alc882_ch_modes,
9680 .need_dac_fix = 1,
9681 .input_mux = &alc882_capture_source,
9682 },
9683 [ALC882_6ST_DIG] = {
9684 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009685 .init_verbs = { alc882_base_init_verbs,
9686 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009687 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9688 .dac_nids = alc882_dac_nids,
9689 .dig_out_nid = ALC882_DIGOUT_NID,
9690 .dig_in_nid = ALC882_DIGIN_NID,
9691 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9692 .channel_mode = alc882_sixstack_modes,
9693 .input_mux = &alc882_capture_source,
9694 },
9695 [ALC882_ARIMA] = {
9696 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009697 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9698 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009699 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9700 .dac_nids = alc882_dac_nids,
9701 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9702 .channel_mode = alc882_sixstack_modes,
9703 .input_mux = &alc882_capture_source,
9704 },
9705 [ALC882_W2JC] = {
9706 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009707 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9708 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009709 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9710 .dac_nids = alc882_dac_nids,
9711 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9712 .channel_mode = alc880_threestack_modes,
9713 .need_dac_fix = 1,
9714 .input_mux = &alc882_capture_source,
9715 .dig_out_nid = ALC882_DIGOUT_NID,
9716 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009717 [ALC885_MBA21] = {
9718 .mixers = { alc885_mba21_mixer },
9719 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9720 .num_dacs = 2,
9721 .dac_nids = alc882_dac_nids,
9722 .channel_mode = alc885_mba21_ch_modes,
9723 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9724 .input_mux = &alc882_capture_source,
9725 .unsol_event = alc_automute_amp_unsol_event,
9726 .setup = alc885_mba21_setup,
9727 .init_hook = alc_automute_amp,
9728 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009729 [ALC885_MBP3] = {
9730 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9731 .init_verbs = { alc885_mbp3_init_verbs,
9732 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009733 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009734 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009735 .hp_nid = 0x04,
9736 .channel_mode = alc885_mbp_4ch_modes,
9737 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009738 .input_mux = &alc882_capture_source,
9739 .dig_out_nid = ALC882_DIGOUT_NID,
9740 .dig_in_nid = ALC882_DIGIN_NID,
9741 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009742 .setup = alc885_mbp3_setup,
9743 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009744 },
9745 [ALC885_MB5] = {
9746 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9747 .init_verbs = { alc885_mb5_init_verbs,
9748 alc880_gpio1_init_verbs },
9749 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9750 .dac_nids = alc882_dac_nids,
9751 .channel_mode = alc885_mb5_6ch_modes,
9752 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9753 .input_mux = &mb5_capture_source,
9754 .dig_out_nid = ALC882_DIGOUT_NID,
9755 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009756 .unsol_event = alc_automute_amp_unsol_event,
9757 .setup = alc885_mb5_setup,
9758 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009759 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009760 [ALC885_MACMINI3] = {
9761 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9762 .init_verbs = { alc885_macmini3_init_verbs,
9763 alc880_gpio1_init_verbs },
9764 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9765 .dac_nids = alc882_dac_nids,
9766 .channel_mode = alc885_macmini3_6ch_modes,
9767 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9768 .input_mux = &macmini3_capture_source,
9769 .dig_out_nid = ALC882_DIGOUT_NID,
9770 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009771 .unsol_event = alc_automute_amp_unsol_event,
9772 .setup = alc885_macmini3_setup,
9773 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009774 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009775 [ALC885_MACPRO] = {
9776 .mixers = { alc882_macpro_mixer },
9777 .init_verbs = { alc882_macpro_init_verbs },
9778 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9779 .dac_nids = alc882_dac_nids,
9780 .dig_out_nid = ALC882_DIGOUT_NID,
9781 .dig_in_nid = ALC882_DIGIN_NID,
9782 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9783 .channel_mode = alc882_ch_modes,
9784 .input_mux = &alc882_capture_source,
9785 .init_hook = alc885_macpro_init_hook,
9786 },
9787 [ALC885_IMAC24] = {
9788 .mixers = { alc885_imac24_mixer },
9789 .init_verbs = { alc885_imac24_init_verbs },
9790 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9791 .dac_nids = alc882_dac_nids,
9792 .dig_out_nid = ALC882_DIGOUT_NID,
9793 .dig_in_nid = ALC882_DIGIN_NID,
9794 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9795 .channel_mode = alc882_ch_modes,
9796 .input_mux = &alc882_capture_source,
9797 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009798 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009799 .init_hook = alc885_imac24_init_hook,
9800 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009801 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009802 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009803 .init_verbs = { alc885_imac91_init_verbs,
9804 alc880_gpio1_init_verbs },
9805 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9806 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009807 .channel_mode = alc885_mba21_ch_modes,
9808 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9809 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009810 .dig_out_nid = ALC882_DIGOUT_NID,
9811 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009812 .unsol_event = alc_automute_amp_unsol_event,
9813 .setup = alc885_imac91_setup,
9814 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009815 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009816 [ALC882_TARGA] = {
9817 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009818 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009819 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009820 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9821 .dac_nids = alc882_dac_nids,
9822 .dig_out_nid = ALC882_DIGOUT_NID,
9823 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9824 .adc_nids = alc882_adc_nids,
9825 .capsrc_nids = alc882_capsrc_nids,
9826 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9827 .channel_mode = alc882_3ST_6ch_modes,
9828 .need_dac_fix = 1,
9829 .input_mux = &alc882_capture_source,
9830 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009831 .setup = alc882_targa_setup,
9832 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009833 },
9834 [ALC882_ASUS_A7J] = {
9835 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009836 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9837 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009838 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9839 .dac_nids = alc882_dac_nids,
9840 .dig_out_nid = ALC882_DIGOUT_NID,
9841 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9842 .adc_nids = alc882_adc_nids,
9843 .capsrc_nids = alc882_capsrc_nids,
9844 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9845 .channel_mode = alc882_3ST_6ch_modes,
9846 .need_dac_fix = 1,
9847 .input_mux = &alc882_capture_source,
9848 },
9849 [ALC882_ASUS_A7M] = {
9850 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009851 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9852 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009853 alc882_asus_a7m_verbs },
9854 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9855 .dac_nids = alc882_dac_nids,
9856 .dig_out_nid = ALC882_DIGOUT_NID,
9857 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9858 .channel_mode = alc880_threestack_modes,
9859 .need_dac_fix = 1,
9860 .input_mux = &alc882_capture_source,
9861 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009862 [ALC883_3ST_2ch_DIG] = {
9863 .mixers = { alc883_3ST_2ch_mixer },
9864 .init_verbs = { alc883_init_verbs },
9865 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9866 .dac_nids = alc883_dac_nids,
9867 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009868 .dig_in_nid = ALC883_DIGIN_NID,
9869 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9870 .channel_mode = alc883_3ST_2ch_modes,
9871 .input_mux = &alc883_capture_source,
9872 },
9873 [ALC883_3ST_6ch_DIG] = {
9874 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9875 .init_verbs = { alc883_init_verbs },
9876 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9877 .dac_nids = alc883_dac_nids,
9878 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009879 .dig_in_nid = ALC883_DIGIN_NID,
9880 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9881 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009882 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009883 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009884 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009885 [ALC883_3ST_6ch] = {
9886 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9887 .init_verbs = { alc883_init_verbs },
9888 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9889 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009890 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9891 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009892 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009893 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009894 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009895 [ALC883_3ST_6ch_INTEL] = {
9896 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9897 .init_verbs = { alc883_init_verbs },
9898 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9899 .dac_nids = alc883_dac_nids,
9900 .dig_out_nid = ALC883_DIGOUT_NID,
9901 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009902 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009903 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9904 .channel_mode = alc883_3ST_6ch_intel_modes,
9905 .need_dac_fix = 1,
9906 .input_mux = &alc883_3stack_6ch_intel,
9907 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009908 [ALC889A_INTEL] = {
9909 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009910 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9911 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009912 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9913 .dac_nids = alc883_dac_nids,
9914 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9915 .adc_nids = alc889_adc_nids,
9916 .dig_out_nid = ALC883_DIGOUT_NID,
9917 .dig_in_nid = ALC883_DIGIN_NID,
9918 .slave_dig_outs = alc883_slave_dig_outs,
9919 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9920 .channel_mode = alc889_8ch_intel_modes,
9921 .capsrc_nids = alc889_capsrc_nids,
9922 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009923 .setup = alc889_automute_setup,
9924 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009925 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009926 .need_dac_fix = 1,
9927 },
9928 [ALC889_INTEL] = {
9929 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9930 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009931 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009932 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9933 .dac_nids = alc883_dac_nids,
9934 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9935 .adc_nids = alc889_adc_nids,
9936 .dig_out_nid = ALC883_DIGOUT_NID,
9937 .dig_in_nid = ALC883_DIGIN_NID,
9938 .slave_dig_outs = alc883_slave_dig_outs,
9939 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9940 .channel_mode = alc889_8ch_intel_modes,
9941 .capsrc_nids = alc889_capsrc_nids,
9942 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009943 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009944 .init_hook = alc889_intel_init_hook,
9945 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009946 .need_dac_fix = 1,
9947 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009948 [ALC883_6ST_DIG] = {
9949 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9950 .init_verbs = { alc883_init_verbs },
9951 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9952 .dac_nids = alc883_dac_nids,
9953 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009954 .dig_in_nid = ALC883_DIGIN_NID,
9955 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9956 .channel_mode = alc883_sixstack_modes,
9957 .input_mux = &alc883_capture_source,
9958 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009959 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009960 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009961 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9962 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009963 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9964 .dac_nids = alc883_dac_nids,
9965 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009966 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9967 .channel_mode = alc883_3ST_6ch_modes,
9968 .need_dac_fix = 1,
9969 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009970 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009971 .setup = alc882_targa_setup,
9972 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009973 },
9974 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009975 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009976 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9977 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009978 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9979 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009980 .adc_nids = alc883_adc_nids_alt,
9981 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009982 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +02009983 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009984 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9985 .channel_mode = alc883_3ST_2ch_modes,
9986 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009987 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009988 .setup = alc882_targa_setup,
9989 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009990 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009991 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009992 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9993 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009994 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009995 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009996 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9997 .dac_nids = alc883_dac_nids,
9998 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9999 .adc_nids = alc883_adc_nids_rev,
10000 .capsrc_nids = alc883_capsrc_nids_rev,
10001 .dig_out_nid = ALC883_DIGOUT_NID,
10002 .dig_in_nid = ALC883_DIGIN_NID,
10003 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10004 .channel_mode = alc883_4ST_8ch_modes,
10005 .need_dac_fix = 1,
10006 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010007 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010008 .setup = alc882_targa_setup,
10009 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010010 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010011 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010012 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010013 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10014 * and the headphone jack. Turn this on and rely on the
10015 * standard mute methods whenever the user wants to turn
10016 * these outputs off.
10017 */
10018 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10019 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10020 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010021 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10022 .channel_mode = alc883_3ST_2ch_modes,
10023 .input_mux = &alc883_capture_source,
10024 },
Tobin Davis2880a862007-08-07 11:50:26 +020010025 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010026 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010027 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010028 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10029 .dac_nids = alc883_dac_nids,
10030 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010031 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10032 .channel_mode = alc883_3ST_2ch_modes,
10033 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010034 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010035 .setup = alc883_acer_aspire_setup,
10036 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010037 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010038 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010039 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010040 alc883_chmode_mixer },
10041 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10042 alc888_acer_aspire_4930g_verbs },
10043 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10044 .dac_nids = alc883_dac_nids,
10045 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10046 .adc_nids = alc883_adc_nids_rev,
10047 .capsrc_nids = alc883_capsrc_nids_rev,
10048 .dig_out_nid = ALC883_DIGOUT_NID,
10049 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10050 .channel_mode = alc883_3ST_6ch_modes,
10051 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010052 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010053 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010054 ARRAY_SIZE(alc888_2_capture_sources),
10055 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010056 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010057 .setup = alc888_acer_aspire_4930g_setup,
10058 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010059 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010060 [ALC888_ACER_ASPIRE_6530G] = {
10061 .mixers = { alc888_acer_aspire_6530_mixer },
10062 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10063 alc888_acer_aspire_6530g_verbs },
10064 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10065 .dac_nids = alc883_dac_nids,
10066 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10067 .adc_nids = alc883_adc_nids_rev,
10068 .capsrc_nids = alc883_capsrc_nids_rev,
10069 .dig_out_nid = ALC883_DIGOUT_NID,
10070 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10071 .channel_mode = alc883_3ST_2ch_modes,
10072 .num_mux_defs =
10073 ARRAY_SIZE(alc888_2_capture_sources),
10074 .input_mux = alc888_acer_aspire_6530_sources,
10075 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010076 .setup = alc888_acer_aspire_6530g_setup,
10077 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010078 },
Hector Martin3b315d72009-06-02 10:54:19 +020010079 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010080 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010081 alc883_chmode_mixer },
10082 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010083 alc889_acer_aspire_8930g_verbs,
10084 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010085 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10086 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010087 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10088 .adc_nids = alc889_adc_nids,
10089 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010090 .dig_out_nid = ALC883_DIGOUT_NID,
10091 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10092 .channel_mode = alc883_3ST_6ch_modes,
10093 .need_dac_fix = 1,
10094 .const_channel_count = 6,
10095 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010096 ARRAY_SIZE(alc889_capture_sources),
10097 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010098 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010099 .setup = alc889_acer_aspire_8930g_setup,
10100 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010101#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010102 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010103#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010104 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010105 [ALC888_ACER_ASPIRE_7730G] = {
10106 .mixers = { alc883_3ST_6ch_mixer,
10107 alc883_chmode_mixer },
10108 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10109 alc888_acer_aspire_7730G_verbs },
10110 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10111 .dac_nids = alc883_dac_nids,
10112 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10113 .adc_nids = alc883_adc_nids_rev,
10114 .capsrc_nids = alc883_capsrc_nids_rev,
10115 .dig_out_nid = ALC883_DIGOUT_NID,
10116 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10117 .channel_mode = alc883_3ST_6ch_modes,
10118 .need_dac_fix = 1,
10119 .const_channel_count = 6,
10120 .input_mux = &alc883_capture_source,
10121 .unsol_event = alc_automute_amp_unsol_event,
10122 .setup = alc888_acer_aspire_6530g_setup,
10123 .init_hook = alc_automute_amp,
10124 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010125 [ALC883_MEDION] = {
10126 .mixers = { alc883_fivestack_mixer,
10127 alc883_chmode_mixer },
10128 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010129 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010130 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10131 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010132 .adc_nids = alc883_adc_nids_alt,
10133 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010134 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010135 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10136 .channel_mode = alc883_sixstack_modes,
10137 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010138 },
Kailang Yang272a5272007-05-14 11:00:38 +020010139 [ALC883_MEDION_MD2] = {
10140 .mixers = { alc883_medion_md2_mixer},
10141 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
10142 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10143 .dac_nids = alc883_dac_nids,
10144 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010145 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10146 .channel_mode = alc883_3ST_2ch_modes,
10147 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010148 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010149 .setup = alc883_medion_md2_setup,
10150 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020010151 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010152 [ALC883_MEDION_WIM2160] = {
10153 .mixers = { alc883_medion_wim2160_mixer },
10154 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10155 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10156 .dac_nids = alc883_dac_nids,
10157 .dig_out_nid = ALC883_DIGOUT_NID,
10158 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10159 .adc_nids = alc883_adc_nids,
10160 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10161 .channel_mode = alc883_3ST_2ch_modes,
10162 .input_mux = &alc883_capture_source,
10163 .unsol_event = alc_automute_amp_unsol_event,
10164 .setup = alc883_medion_wim2160_setup,
10165 .init_hook = alc_automute_amp,
10166 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010167 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010168 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010169 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10170 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10171 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010172 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10173 .channel_mode = alc883_3ST_2ch_modes,
10174 .input_mux = &alc883_capture_source,
10175 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010176 [ALC883_CLEVO_M540R] = {
10177 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10178 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10179 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10180 .dac_nids = alc883_dac_nids,
10181 .dig_out_nid = ALC883_DIGOUT_NID,
10182 .dig_in_nid = ALC883_DIGIN_NID,
10183 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10184 .channel_mode = alc883_3ST_6ch_clevo_modes,
10185 .need_dac_fix = 1,
10186 .input_mux = &alc883_capture_source,
10187 /* This machine has the hardware HP auto-muting, thus
10188 * we need no software mute via unsol event
10189 */
10190 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010191 [ALC883_CLEVO_M720] = {
10192 .mixers = { alc883_clevo_m720_mixer },
10193 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010194 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10195 .dac_nids = alc883_dac_nids,
10196 .dig_out_nid = ALC883_DIGOUT_NID,
10197 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10198 .channel_mode = alc883_3ST_2ch_modes,
10199 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010200 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010201 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010202 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010203 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010204 [ALC883_LENOVO_101E_2ch] = {
10205 .mixers = { alc883_lenovo_101e_2ch_mixer},
10206 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10207 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10208 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010209 .adc_nids = alc883_adc_nids_alt,
10210 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010211 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010212 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10213 .channel_mode = alc883_3ST_2ch_modes,
10214 .input_mux = &alc883_lenovo_101e_capture_source,
10215 .unsol_event = alc883_lenovo_101e_unsol_event,
10216 .init_hook = alc883_lenovo_101e_all_automute,
10217 },
Kailang Yang272a5272007-05-14 11:00:38 +020010218 [ALC883_LENOVO_NB0763] = {
10219 .mixers = { alc883_lenovo_nb0763_mixer },
10220 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10221 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10222 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010223 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10224 .channel_mode = alc883_3ST_2ch_modes,
10225 .need_dac_fix = 1,
10226 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010227 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010228 .setup = alc883_medion_md2_setup,
10229 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010230 },
10231 [ALC888_LENOVO_MS7195_DIG] = {
10232 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10233 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10234 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10235 .dac_nids = alc883_dac_nids,
10236 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010237 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10238 .channel_mode = alc883_3ST_6ch_modes,
10239 .need_dac_fix = 1,
10240 .input_mux = &alc883_capture_source,
10241 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10242 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010243 },
10244 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010245 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010246 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10247 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10248 .dac_nids = alc883_dac_nids,
10249 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010250 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10251 .channel_mode = alc883_3ST_2ch_modes,
10252 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010253 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010254 .setup = alc883_haier_w66_setup,
10255 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010256 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010257 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010258 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010259 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010260 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10261 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010262 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10263 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010264 .need_dac_fix = 1,
10265 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010266 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010267 .setup = alc888_3st_hp_setup,
10268 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010269 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010270 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010271 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010272 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10273 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10274 .dac_nids = alc883_dac_nids,
10275 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010276 .dig_in_nid = ALC883_DIGIN_NID,
10277 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10278 .channel_mode = alc883_sixstack_modes,
10279 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010280 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010281 .setup = alc888_6st_dell_setup,
10282 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010283 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010284 [ALC883_MITAC] = {
10285 .mixers = { alc883_mitac_mixer },
10286 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10287 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10288 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010289 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10290 .channel_mode = alc883_3ST_2ch_modes,
10291 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010292 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010293 .setup = alc883_mitac_setup,
10294 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010295 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010296 [ALC883_FUJITSU_PI2515] = {
10297 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10298 .init_verbs = { alc883_init_verbs,
10299 alc883_2ch_fujitsu_pi2515_verbs},
10300 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10301 .dac_nids = alc883_dac_nids,
10302 .dig_out_nid = ALC883_DIGOUT_NID,
10303 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10304 .channel_mode = alc883_3ST_2ch_modes,
10305 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010306 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010307 .setup = alc883_2ch_fujitsu_pi2515_setup,
10308 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010309 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010310 [ALC888_FUJITSU_XA3530] = {
10311 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10312 .init_verbs = { alc883_init_verbs,
10313 alc888_fujitsu_xa3530_verbs },
10314 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10315 .dac_nids = alc883_dac_nids,
10316 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10317 .adc_nids = alc883_adc_nids_rev,
10318 .capsrc_nids = alc883_capsrc_nids_rev,
10319 .dig_out_nid = ALC883_DIGOUT_NID,
10320 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10321 .channel_mode = alc888_4ST_8ch_intel_modes,
10322 .num_mux_defs =
10323 ARRAY_SIZE(alc888_2_capture_sources),
10324 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010325 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010326 .setup = alc888_fujitsu_xa3530_setup,
10327 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010328 },
Kailang Yange2757d52008-08-26 13:17:46 +020010329 [ALC888_LENOVO_SKY] = {
10330 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10331 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10332 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10333 .dac_nids = alc883_dac_nids,
10334 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010335 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10336 .channel_mode = alc883_sixstack_modes,
10337 .need_dac_fix = 1,
10338 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010339 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010340 .setup = alc888_lenovo_sky_setup,
10341 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010342 },
10343 [ALC888_ASUS_M90V] = {
10344 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10345 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10346 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10347 .dac_nids = alc883_dac_nids,
10348 .dig_out_nid = ALC883_DIGOUT_NID,
10349 .dig_in_nid = ALC883_DIGIN_NID,
10350 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10351 .channel_mode = alc883_3ST_6ch_modes,
10352 .need_dac_fix = 1,
10353 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010354 .unsol_event = alc_sku_unsol_event,
10355 .setup = alc883_mode2_setup,
10356 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010357 },
10358 [ALC888_ASUS_EEE1601] = {
10359 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010360 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010361 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10362 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10363 .dac_nids = alc883_dac_nids,
10364 .dig_out_nid = ALC883_DIGOUT_NID,
10365 .dig_in_nid = ALC883_DIGIN_NID,
10366 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10367 .channel_mode = alc883_3ST_2ch_modes,
10368 .need_dac_fix = 1,
10369 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010370 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010371 .init_hook = alc883_eee1601_inithook,
10372 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010373 [ALC1200_ASUS_P5Q] = {
10374 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10375 .init_verbs = { alc883_init_verbs },
10376 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10377 .dac_nids = alc883_dac_nids,
10378 .dig_out_nid = ALC1200_DIGOUT_NID,
10379 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010380 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010381 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10382 .channel_mode = alc883_sixstack_modes,
10383 .input_mux = &alc883_capture_source,
10384 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010385 [ALC889A_MB31] = {
10386 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10387 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10388 alc880_gpio1_init_verbs },
10389 .adc_nids = alc883_adc_nids,
10390 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010391 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010392 .dac_nids = alc883_dac_nids,
10393 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10394 .channel_mode = alc889A_mb31_6ch_modes,
10395 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10396 .input_mux = &alc889A_mb31_capture_source,
10397 .dig_out_nid = ALC883_DIGOUT_NID,
10398 .unsol_event = alc889A_mb31_unsol_event,
10399 .init_hook = alc889A_mb31_automute,
10400 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010401 [ALC883_SONY_VAIO_TT] = {
10402 .mixers = { alc883_vaiott_mixer },
10403 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10404 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10405 .dac_nids = alc883_dac_nids,
10406 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10407 .channel_mode = alc883_3ST_2ch_modes,
10408 .input_mux = &alc883_capture_source,
10409 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010410 .setup = alc883_vaiott_setup,
10411 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010412 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010413};
10414
10415
10416/*
Takashi Iwai4953550a2009-06-30 15:28:30 +020010417 * Pin config fixes
10418 */
10419enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010420 PINFIX_ABIT_AW9D_MAX,
10421 PINFIX_PB_M5210,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010422};
10423
10424static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
10425 { 0x15, 0x01080104 }, /* side */
10426 { 0x16, 0x01011012 }, /* rear */
10427 { 0x17, 0x01016011 }, /* clfe */
10428 { }
10429};
10430
Takashi Iwai954a29c2010-07-30 10:55:44 +020010431static const struct hda_verb pb_m5210_verbs[] = {
10432 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10433 {}
10434};
10435
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010436static const struct alc_fixup alc882_fixups[] = {
10437 [PINFIX_ABIT_AW9D_MAX] = {
10438 .pins = alc882_abit_aw9d_pinfix
10439 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010440 [PINFIX_PB_M5210] = {
10441 .verbs = pb_m5210_verbs
10442 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010443};
10444
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010445static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010446 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010447 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
10448 {}
10449};
10450
10451/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010452 * BIOS auto configuration
10453 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010454static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10455 const struct auto_pin_cfg *cfg)
10456{
10457 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10458}
10459
Takashi Iwai4953550a2009-06-30 15:28:30 +020010460static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010461 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010462 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010463{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010464 int idx;
10465
Takashi Iwai489008c2010-04-07 09:06:00 +020010466 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010467 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010468
Takashi Iwai489008c2010-04-07 09:06:00 +020010469 if (dac == 0x25)
10470 idx = 4;
10471 else if (dac >= 0x02 && dac <= 0x05)
10472 idx = dac - 2;
10473 else
10474 return;
10475 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010476}
10477
Takashi Iwai4953550a2009-06-30 15:28:30 +020010478static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010479{
10480 struct alc_spec *spec = codec->spec;
10481 int i;
10482
10483 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010484 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010485 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010486 if (nid)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010487 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010488 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010489 }
10490}
10491
Takashi Iwai4953550a2009-06-30 15:28:30 +020010492static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010493{
10494 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010495 hda_nid_t pin, dac;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010496
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010497 pin = spec->autocfg.hp_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010498 if (pin) {
10499 dac = spec->multiout.hp_nid;
10500 if (!dac)
10501 dac = spec->multiout.dac_nids[0]; /* to front */
10502 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10503 }
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010504 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010505 if (pin) {
10506 dac = spec->multiout.extra_out_nid[0];
10507 if (!dac)
10508 dac = spec->multiout.dac_nids[0]; /* to front */
10509 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10510 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010511}
10512
Takashi Iwai4953550a2009-06-30 15:28:30 +020010513static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010514{
10515 struct alc_spec *spec = codec->spec;
10516 int i;
10517
10518 for (i = 0; i < AUTO_PIN_LAST; i++) {
10519 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010520 if (!nid)
10521 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +020010522 alc_set_input_pin(codec, nid, i);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010523 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10524 snd_hda_codec_write(codec, nid, 0,
10525 AC_VERB_SET_AMP_GAIN_MUTE,
10526 AMP_OUT_MUTE);
10527 }
10528}
10529
10530static void alc882_auto_init_input_src(struct hda_codec *codec)
10531{
10532 struct alc_spec *spec = codec->spec;
10533 int c;
10534
10535 for (c = 0; c < spec->num_adc_nids; c++) {
10536 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10537 hda_nid_t nid = spec->capsrc_nids[c];
10538 unsigned int mux_idx;
10539 const struct hda_input_mux *imux;
10540 int conns, mute, idx, item;
10541
10542 conns = snd_hda_get_connections(codec, nid, conn_list,
10543 ARRAY_SIZE(conn_list));
10544 if (conns < 0)
10545 continue;
10546 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10547 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010548 if (!imux->num_items && mux_idx > 0)
10549 imux = &spec->input_mux[0];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010550 for (idx = 0; idx < conns; idx++) {
10551 /* if the current connection is the selected one,
10552 * unmute it as default - otherwise mute it
10553 */
10554 mute = AMP_IN_MUTE(idx);
10555 for (item = 0; item < imux->num_items; item++) {
10556 if (imux->items[item].index == idx) {
10557 if (spec->cur_mux[c] == item)
10558 mute = AMP_IN_UNMUTE(idx);
10559 break;
10560 }
10561 }
10562 /* check if we have a selector or mixer
10563 * we could check for the widget type instead, but
10564 * just check for Amp-In presence (in case of mixer
10565 * without amp-in there is something wrong, this
10566 * function shouldn't be used or capsrc nid is wrong)
10567 */
10568 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010569 snd_hda_codec_write(codec, nid, 0,
10570 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010571 mute);
10572 else if (mute != AMP_IN_MUTE(idx))
10573 snd_hda_codec_write(codec, nid, 0,
10574 AC_VERB_SET_CONNECT_SEL,
10575 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010576 }
10577 }
10578}
10579
Takashi Iwai4953550a2009-06-30 15:28:30 +020010580/* add mic boosts if needed */
10581static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010582{
10583 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010584 int err;
10585 hda_nid_t nid;
10586
10587 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
10588 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10589 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10590 "Mic Boost",
10591 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10592 if (err < 0)
10593 return err;
10594 }
10595 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
10596 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10597 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10598 "Front Mic Boost",
10599 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10600 if (err < 0)
10601 return err;
10602 }
10603 return 0;
10604}
10605
10606/* almost identical with ALC880 parser... */
10607static int alc882_parse_auto_config(struct hda_codec *codec)
10608{
10609 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010610 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010611 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010612
Takashi Iwai05f5f472009-08-25 13:10:18 +020010613 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10614 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010615 if (err < 0)
10616 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010617 if (!spec->autocfg.line_outs)
10618 return 0; /* can't find valid BIOS pin config */
10619
10620 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10621 if (err < 0)
10622 return err;
10623 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10624 if (err < 0)
10625 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010626 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10627 "Headphone");
10628 if (err < 0)
10629 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010630 err = alc880_auto_create_extra_out(spec,
10631 spec->autocfg.speaker_pins[0],
10632 "Speaker");
10633 if (err < 0)
10634 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010635 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10636 if (err < 0)
10637 return err;
10638
10639 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10640
Takashi Iwai757899a2010-07-30 10:48:14 +020010641 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010642
10643 if (spec->kctls.list)
10644 add_mixer(spec, spec->kctls.list);
10645
10646 add_verb(spec, alc883_auto_init_verbs);
10647 /* if ADC 0x07 is available, initialize it, too */
10648 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10649 add_verb(spec, alc882_adc1_init_verbs);
10650
10651 spec->num_mux_defs = 1;
10652 spec->input_mux = &spec->private_imux[0];
10653
Kailang Yang6227cdc2010-02-25 08:36:52 +010010654 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010655
10656 err = alc_auto_add_mic_boost(codec);
10657 if (err < 0)
10658 return err;
10659
Takashi Iwai776e1842007-08-29 15:07:11 +020010660 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010661}
10662
10663/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010664static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010665{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010666 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010667 alc882_auto_init_multi_out(codec);
10668 alc882_auto_init_hp_out(codec);
10669 alc882_auto_init_analog_input(codec);
10670 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010671 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010672 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010673 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010674}
10675
Takashi Iwai4953550a2009-06-30 15:28:30 +020010676static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010677{
10678 struct alc_spec *spec;
10679 int err, board_config;
10680
10681 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10682 if (spec == NULL)
10683 return -ENOMEM;
10684
10685 codec->spec = spec;
10686
Kailang Yangda00c242010-03-19 11:23:45 +010010687 alc_auto_parse_customize_define(codec);
10688
Takashi Iwai4953550a2009-06-30 15:28:30 +020010689 switch (codec->vendor_id) {
10690 case 0x10ec0882:
10691 case 0x10ec0885:
10692 break;
10693 default:
10694 /* ALC883 and variants */
10695 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10696 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010697 }
10698
Takashi Iwai4953550a2009-06-30 15:28:30 +020010699 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10700 alc882_models,
10701 alc882_cfg_tbl);
10702
10703 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10704 board_config = snd_hda_check_board_codec_sid_config(codec,
10705 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10706
10707 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010708 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020010709 codec->chip_name);
10710 board_config = ALC882_AUTO;
10711 }
10712
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010713 if (board_config == ALC882_AUTO)
10714 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010715
10716 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010717 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010718 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010719 if (err < 0) {
10720 alc_free(codec);
10721 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010722 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010723 printk(KERN_INFO
10724 "hda_codec: Cannot set up configuration "
10725 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020010726 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010727 }
10728 }
10729
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010730 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020010731 err = snd_hda_attach_beep_device(codec, 0x1);
10732 if (err < 0) {
10733 alc_free(codec);
10734 return err;
10735 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010736 }
10737
Takashi Iwai4953550a2009-06-30 15:28:30 +020010738 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010739 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010740
Takashi Iwai4953550a2009-06-30 15:28:30 +020010741 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10742 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10743 /* FIXME: setup DAC5 */
10744 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10745 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10746
10747 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10748 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10749
Takashi Iwai4953550a2009-06-30 15:28:30 +020010750 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010751 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010752 spec->num_adc_nids = 0;
10753 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010754 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010755 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010756 hda_nid_t items[16];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010757 hda_nid_t nid = alc882_adc_nids[i];
10758 unsigned int wcap = get_wcaps(codec, nid);
10759 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010760 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010761 if (wcap != AC_WID_AUD_IN)
10762 continue;
10763 spec->private_adc_nids[spec->num_adc_nids] = nid;
10764 err = snd_hda_get_connections(codec, nid, &cap, 1);
10765 if (err < 0)
10766 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010767 err = snd_hda_get_connections(codec, cap, items,
10768 ARRAY_SIZE(items));
10769 if (err < 0)
10770 continue;
10771 for (j = 0; j < imux->num_items; j++)
10772 if (imux->items[j].index >= err)
10773 break;
10774 if (j < imux->num_items)
10775 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010776 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10777 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010778 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010779 spec->adc_nids = spec->private_adc_nids;
10780 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010781 }
10782
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010783 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010010784
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010785 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010010786 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010787
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010788 if (board_config == ALC882_AUTO)
10789 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
10790
Takashi Iwai2134ea42008-01-10 16:53:55 +010010791 spec->vmaster_nid = 0x0c;
10792
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010793 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010794 if (board_config == ALC882_AUTO)
10795 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010796#ifdef CONFIG_SND_HDA_POWER_SAVE
10797 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010798 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010799#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010800
10801 return 0;
10802}
10803
Takashi Iwai4953550a2009-06-30 15:28:30 +020010804
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010805/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010806 * ALC262 support
10807 */
10808
10809#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10810#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10811
10812#define alc262_dac_nids alc260_dac_nids
10813#define alc262_adc_nids alc882_adc_nids
10814#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010815#define alc262_capsrc_nids alc882_capsrc_nids
10816#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010817
10818#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010819#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010820
Kailang Yang4e555fe2008-08-26 13:05:55 +020010821static hda_nid_t alc262_dmic_adc_nids[1] = {
10822 /* ADC0 */
10823 0x09
10824};
10825
10826static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10827
Kailang Yangdf694da2005-12-05 19:42:22 +010010828static struct snd_kcontrol_new alc262_base_mixer[] = {
10829 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10830 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10831 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10832 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10833 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10834 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10835 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10836 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010837 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010838 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10839 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010840 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010841 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10842 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10843 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10844 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010845 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010846};
10847
Takashi Iwaice875f02008-01-28 18:17:43 +010010848/* update HP, line and mono-out pins according to the master switch */
10849static void alc262_hp_master_update(struct hda_codec *codec)
10850{
10851 struct alc_spec *spec = codec->spec;
10852 int val = spec->master_sw;
10853
10854 /* HP & line-out */
10855 snd_hda_codec_write_cache(codec, 0x1b, 0,
10856 AC_VERB_SET_PIN_WIDGET_CONTROL,
10857 val ? PIN_HP : 0);
10858 snd_hda_codec_write_cache(codec, 0x15, 0,
10859 AC_VERB_SET_PIN_WIDGET_CONTROL,
10860 val ? PIN_HP : 0);
10861 /* mono (speaker) depending on the HP jack sense */
10862 val = val && !spec->jack_present;
10863 snd_hda_codec_write_cache(codec, 0x16, 0,
10864 AC_VERB_SET_PIN_WIDGET_CONTROL,
10865 val ? PIN_OUT : 0);
10866}
10867
10868static void alc262_hp_bpc_automute(struct hda_codec *codec)
10869{
10870 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010871
10872 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010873 alc262_hp_master_update(codec);
10874}
10875
10876static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10877{
10878 if ((res >> 26) != ALC880_HP_EVENT)
10879 return;
10880 alc262_hp_bpc_automute(codec);
10881}
10882
10883static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10884{
10885 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010886
10887 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010888 alc262_hp_master_update(codec);
10889}
10890
10891static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10892 unsigned int res)
10893{
10894 if ((res >> 26) != ALC880_HP_EVENT)
10895 return;
10896 alc262_hp_wildwest_automute(codec);
10897}
10898
Takashi Iwaib72519b2009-05-08 14:31:55 +020010899#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010900
10901static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10902 struct snd_ctl_elem_value *ucontrol)
10903{
10904 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10905 struct alc_spec *spec = codec->spec;
10906 int val = !!*ucontrol->value.integer.value;
10907
10908 if (val == spec->master_sw)
10909 return 0;
10910 spec->master_sw = val;
10911 alc262_hp_master_update(codec);
10912 return 1;
10913}
10914
Takashi Iwaib72519b2009-05-08 14:31:55 +020010915#define ALC262_HP_MASTER_SWITCH \
10916 { \
10917 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10918 .name = "Master Playback Switch", \
10919 .info = snd_ctl_boolean_mono_info, \
10920 .get = alc262_hp_master_sw_get, \
10921 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010922 }, \
10923 { \
10924 .iface = NID_MAPPING, \
10925 .name = "Master Playback Switch", \
10926 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010927 }
10928
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010929
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010930static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010931 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010932 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10933 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10934 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010935 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10936 HDA_OUTPUT),
10937 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10938 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010939 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10940 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010941 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010942 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10943 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010944 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010945 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10946 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10947 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10948 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010949 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10950 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10951 { } /* end */
10952};
10953
Kailang Yangcd7509a2007-01-26 18:33:17 +010010954static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010955 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010956 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10957 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10958 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10959 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010960 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10961 HDA_OUTPUT),
10962 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10963 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010964 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10965 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010966 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010967 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10968 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10969 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10970 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010971 { } /* end */
10972};
10973
10974static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10975 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10976 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010977 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010978 { } /* end */
10979};
10980
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010981/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010982static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010983{
10984 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010985
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010986 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010010987 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010988}
10989
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010990static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010991 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10992 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010993 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10994 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10995 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10996 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10997 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10998 { } /* end */
10999};
11000
11001static struct hda_verb alc262_hp_t5735_verbs[] = {
11002 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11003 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11004
11005 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11006 { }
11007};
11008
Kailang Yang8c427222008-01-10 13:03:59 +010011009static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011010 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11011 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011012 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11013 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011014 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11015 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11016 { } /* end */
11017};
11018
11019static struct hda_verb alc262_hp_rp5700_verbs[] = {
11020 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11021 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11022 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11023 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11024 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11025 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11026 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11027 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11028 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11029 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11030 {}
11031};
11032
11033static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11034 .num_items = 1,
11035 .items = {
11036 { "Line", 0x1 },
11037 },
11038};
11039
Takashi Iwai42171c12009-05-08 14:11:43 +020011040/* bind hp and internal speaker mute (with plug check) as master switch */
11041static void alc262_hippo_master_update(struct hda_codec *codec)
11042{
11043 struct alc_spec *spec = codec->spec;
11044 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11045 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11046 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11047 unsigned int mute;
11048
11049 /* HP */
11050 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11051 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11052 HDA_AMP_MUTE, mute);
11053 /* mute internal speaker per jack sense */
11054 if (spec->jack_present)
11055 mute = HDA_AMP_MUTE;
11056 if (line_nid)
11057 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11058 HDA_AMP_MUTE, mute);
11059 if (speaker_nid && speaker_nid != line_nid)
11060 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11061 HDA_AMP_MUTE, mute);
11062}
11063
11064#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11065
11066static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11067 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011068{
11069 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011070 struct alc_spec *spec = codec->spec;
11071 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011072
Takashi Iwai42171c12009-05-08 14:11:43 +020011073 if (val == spec->master_sw)
11074 return 0;
11075 spec->master_sw = val;
11076 alc262_hippo_master_update(codec);
11077 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011078}
Takashi Iwai5b319542007-07-26 11:49:22 +020011079
Takashi Iwai42171c12009-05-08 14:11:43 +020011080#define ALC262_HIPPO_MASTER_SWITCH \
11081 { \
11082 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11083 .name = "Master Playback Switch", \
11084 .info = snd_ctl_boolean_mono_info, \
11085 .get = alc262_hippo_master_sw_get, \
11086 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011087 }, \
11088 { \
11089 .iface = NID_MAPPING, \
11090 .name = "Master Playback Switch", \
11091 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11092 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011093 }
11094
11095static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11096 ALC262_HIPPO_MASTER_SWITCH,
11097 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11098 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11099 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11100 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11101 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11104 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11105 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11106 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11107 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11108 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11109 { } /* end */
11110};
11111
11112static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11113 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11114 ALC262_HIPPO_MASTER_SWITCH,
11115 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11116 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11117 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11118 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11119 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11120 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11121 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11122 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11123 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11124 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11125 { } /* end */
11126};
11127
11128/* mute/unmute internal speaker according to the hp jack and mute state */
11129static void alc262_hippo_automute(struct hda_codec *codec)
11130{
11131 struct alc_spec *spec = codec->spec;
11132 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011133
Wu Fengguang864f92b2009-11-18 12:38:02 +080011134 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011135 alc262_hippo_master_update(codec);
11136}
11137
11138static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11139{
11140 if ((res >> 26) != ALC880_HP_EVENT)
11141 return;
11142 alc262_hippo_automute(codec);
11143}
11144
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011145static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011146{
11147 struct alc_spec *spec = codec->spec;
11148
11149 spec->autocfg.hp_pins[0] = 0x15;
11150 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011151}
11152
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011153static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011154{
11155 struct alc_spec *spec = codec->spec;
11156
11157 spec->autocfg.hp_pins[0] = 0x1b;
11158 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011159}
11160
11161
Kailang Yang272a5272007-05-14 11:00:38 +020011162static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011163 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011164 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011165 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11166 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11167 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11168 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11169 { } /* end */
11170};
11171
Kailang Yang83c34212007-07-05 11:43:05 +020011172static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011173 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11174 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011175 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11176 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11177 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11178 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11179 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11180 { } /* end */
11181};
Kailang Yang272a5272007-05-14 11:00:38 +020011182
Tony Vroonba340e82009-02-02 19:01:30 +000011183static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11184 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11185 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11186 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11187 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11188 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11189 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11190 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11191 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11192 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11193 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11194 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11195 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11196 { } /* end */
11197};
11198
11199static struct hda_verb alc262_tyan_verbs[] = {
11200 /* Headphone automute */
11201 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11202 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11203 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11204
11205 /* P11 AUX_IN, white 4-pin connector */
11206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11207 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11208 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11209 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11210
11211 {}
11212};
11213
11214/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011215static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011216{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011217 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011218
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011219 spec->autocfg.hp_pins[0] = 0x1b;
11220 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011221}
11222
Tony Vroonba340e82009-02-02 19:01:30 +000011223
Kailang Yangdf694da2005-12-05 19:42:22 +010011224#define alc262_capture_mixer alc882_capture_mixer
11225#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11226
11227/*
11228 * generic initialization of ADC, input mixers and output mixers
11229 */
11230static struct hda_verb alc262_init_verbs[] = {
11231 /*
11232 * Unmute ADC0-2 and set the default input to mic-in
11233 */
11234 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11235 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11236 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11237 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11238 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11239 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11240
Takashi Iwaicb53c622007-08-10 17:21:45 +020011241 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011242 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011243 * Note: PASD motherboards uses the Line In 2 as the input for
11244 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011245 */
11246 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011247 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11250 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011252
11253 /*
11254 * Set up output mixers (0x0c - 0x0e)
11255 */
11256 /* set vol=0 to output mixers */
11257 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11258 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11259 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11260 /* set up input amps for analog loopback */
11261 /* Amp Indices: DAC = 0, mixer = 1 */
11262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11264 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11265 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11266 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11267 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11268
11269 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11270 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11271 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11272 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11273 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11274 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11275
11276 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11277 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11278 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11279 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11280 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011281
Kailang Yangdf694da2005-12-05 19:42:22 +010011282 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11283 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011284
Kailang Yangdf694da2005-12-05 19:42:22 +010011285 /* FIXME: use matrix-type input source selection */
11286 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11287 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11288 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11289 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11290 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11291 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11292 /* Input mixer2 */
11293 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11294 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11295 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11296 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11297 /* Input mixer3 */
11298 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11300 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011301 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011302
11303 { }
11304};
11305
Kailang Yang4e555fe2008-08-26 13:05:55 +020011306static struct hda_verb alc262_eapd_verbs[] = {
11307 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11308 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11309 { }
11310};
11311
Kailang Yangccc656c2006-10-17 12:32:26 +020011312static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11313 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11314 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11315 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11316
11317 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11318 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11319 {}
11320};
11321
Kailang Yang272a5272007-05-14 11:00:38 +020011322static struct hda_verb alc262_sony_unsol_verbs[] = {
11323 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11324 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11325 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11326
11327 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11328 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011329 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011330};
11331
Kailang Yang4e555fe2008-08-26 13:05:55 +020011332static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11333 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11334 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11335 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11336 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11337 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011338 { } /* end */
11339};
11340
11341static struct hda_verb alc262_toshiba_s06_verbs[] = {
11342 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11343 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11344 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11345 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11346 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11347 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11348 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11349 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11350 {}
11351};
11352
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011353static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011354{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011355 struct alc_spec *spec = codec->spec;
11356
11357 spec->autocfg.hp_pins[0] = 0x15;
11358 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011359 spec->ext_mic.pin = 0x18;
11360 spec->ext_mic.mux_idx = 0;
11361 spec->int_mic.pin = 0x12;
11362 spec->int_mic.mux_idx = 9;
11363 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011364}
11365
Takashi Iwai834be882006-03-01 14:16:17 +010011366/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011367 * nec model
11368 * 0x15 = headphone
11369 * 0x16 = internal speaker
11370 * 0x18 = external mic
11371 */
11372
11373static struct snd_kcontrol_new alc262_nec_mixer[] = {
11374 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11375 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11376
11377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11378 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11379 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11380
11381 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11382 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11383 { } /* end */
11384};
11385
11386static struct hda_verb alc262_nec_verbs[] = {
11387 /* Unmute Speaker */
11388 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11389
11390 /* Headphone */
11391 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11392 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11393
11394 /* External mic to headphone */
11395 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11396 /* External mic to speaker */
11397 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11398 {}
11399};
11400
11401/*
Takashi Iwai834be882006-03-01 14:16:17 +010011402 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011403 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11404 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011405 */
11406
11407#define ALC_HP_EVENT 0x37
11408
11409static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11410 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11411 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011412 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11413 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011414 {}
11415};
11416
Jiang zhe0e31daf2008-03-20 12:12:39 +010011417static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11418 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11419 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11420 {}
11421};
11422
Daniel T Chene2595322009-12-19 18:19:02 -050011423static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11424 /* Front Mic pin: input vref at 50% */
11425 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11426 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11427 {}
11428};
11429
Takashi Iwai834be882006-03-01 14:16:17 +010011430static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011431 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011432 .items = {
11433 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011434 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011435 { "CD", 0x4 },
11436 },
11437};
11438
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011439static struct hda_input_mux alc262_HP_capture_source = {
11440 .num_items = 5,
11441 .items = {
11442 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011443 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011444 { "Line", 0x2 },
11445 { "CD", 0x4 },
11446 { "AUX IN", 0x6 },
11447 },
11448};
11449
zhejiangaccbe492007-08-31 12:36:05 +020011450static struct hda_input_mux alc262_HP_D7000_capture_source = {
11451 .num_items = 4,
11452 .items = {
11453 { "Mic", 0x0 },
11454 { "Front Mic", 0x2 },
11455 { "Line", 0x1 },
11456 { "CD", 0x4 },
11457 },
11458};
11459
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011460/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011461static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11462{
11463 struct alc_spec *spec = codec->spec;
11464 unsigned int mute;
11465
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011466 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011467 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11468 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011469 spec->sense_updated = 1;
11470 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011471 /* unmute internal speaker only if both HPs are unplugged and
11472 * master switch is on
11473 */
11474 if (spec->jack_present)
11475 mute = HDA_AMP_MUTE;
11476 else
Takashi Iwai834be882006-03-01 14:16:17 +010011477 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011478 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11479 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011480}
11481
11482/* unsolicited event for HP jack sensing */
11483static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11484 unsigned int res)
11485{
11486 if ((res >> 26) != ALC_HP_EVENT)
11487 return;
11488 alc262_fujitsu_automute(codec, 1);
11489}
11490
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011491static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11492{
11493 alc262_fujitsu_automute(codec, 1);
11494}
11495
Takashi Iwai834be882006-03-01 14:16:17 +010011496/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011497static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11498 .ops = &snd_hda_bind_vol,
11499 .values = {
11500 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11501 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11502 0
11503 },
11504};
Takashi Iwai834be882006-03-01 14:16:17 +010011505
Jiang zhe0e31daf2008-03-20 12:12:39 +010011506/* mute/unmute internal speaker according to the hp jack and mute state */
11507static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11508{
11509 struct alc_spec *spec = codec->spec;
11510 unsigned int mute;
11511
11512 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011513 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011514 spec->sense_updated = 1;
11515 }
11516 if (spec->jack_present) {
11517 /* mute internal speaker */
11518 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11519 HDA_AMP_MUTE, HDA_AMP_MUTE);
11520 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11521 HDA_AMP_MUTE, HDA_AMP_MUTE);
11522 } else {
11523 /* unmute internal speaker if necessary */
11524 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11525 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11526 HDA_AMP_MUTE, mute);
11527 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11528 HDA_AMP_MUTE, mute);
11529 }
11530}
11531
11532/* unsolicited event for HP jack sensing */
11533static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11534 unsigned int res)
11535{
11536 if ((res >> 26) != ALC_HP_EVENT)
11537 return;
11538 alc262_lenovo_3000_automute(codec, 1);
11539}
11540
Takashi Iwai8de56b72009-07-24 16:51:47 +020011541static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11542 int dir, int idx, long *valp)
11543{
11544 int i, change = 0;
11545
11546 for (i = 0; i < 2; i++, valp++)
11547 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11548 HDA_AMP_MUTE,
11549 *valp ? 0 : HDA_AMP_MUTE);
11550 return change;
11551}
11552
Takashi Iwai834be882006-03-01 14:16:17 +010011553/* bind hp and internal speaker mute (with plug check) */
11554static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11555 struct snd_ctl_elem_value *ucontrol)
11556{
11557 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11558 long *valp = ucontrol->value.integer.value;
11559 int change;
11560
Takashi Iwai8de56b72009-07-24 16:51:47 +020011561 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11562 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011563 if (change)
11564 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011565 return change;
11566}
11567
11568static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011569 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011570 {
11571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11572 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011573 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011574 .info = snd_hda_mixer_amp_switch_info,
11575 .get = snd_hda_mixer_amp_switch_get,
11576 .put = alc262_fujitsu_master_sw_put,
11577 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11578 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011579 {
11580 .iface = NID_MAPPING,
11581 .name = "Master Playback Switch",
11582 .private_value = 0x1b,
11583 },
Takashi Iwai834be882006-03-01 14:16:17 +010011584 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11585 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11586 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11587 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11588 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011589 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11590 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11591 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011592 { } /* end */
11593};
11594
Jiang zhe0e31daf2008-03-20 12:12:39 +010011595/* bind hp and internal speaker mute (with plug check) */
11596static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11597 struct snd_ctl_elem_value *ucontrol)
11598{
11599 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11600 long *valp = ucontrol->value.integer.value;
11601 int change;
11602
Takashi Iwai8de56b72009-07-24 16:51:47 +020011603 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011604 if (change)
11605 alc262_lenovo_3000_automute(codec, 0);
11606 return change;
11607}
11608
11609static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11610 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11611 {
11612 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11613 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011614 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011615 .info = snd_hda_mixer_amp_switch_info,
11616 .get = snd_hda_mixer_amp_switch_get,
11617 .put = alc262_lenovo_3000_master_sw_put,
11618 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11619 },
11620 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11621 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11622 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11623 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11624 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11625 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11626 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11627 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11628 { } /* end */
11629};
11630
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011631static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11632 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011633 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011634 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11635 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11636 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11637 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11638 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11639 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11640 { } /* end */
11641};
11642
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011643/* additional init verbs for Benq laptops */
11644static struct hda_verb alc262_EAPD_verbs[] = {
11645 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11646 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11647 {}
11648};
11649
Kailang Yang83c34212007-07-05 11:43:05 +020011650static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11651 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11652 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11653
11654 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11655 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11656 {}
11657};
11658
Tobin Davisf651b502007-10-26 12:40:47 +020011659/* Samsung Q1 Ultra Vista model setup */
11660static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011661 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11662 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011663 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11664 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11665 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011666 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011667 { } /* end */
11668};
11669
11670static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011671 /* output mixer */
11672 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11673 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11674 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11675 /* speaker */
11676 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11677 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11678 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11679 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11680 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011681 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011682 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11683 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11684 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11685 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11686 /* internal mic */
11687 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11688 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11689 /* ADC, choose mic */
11690 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11691 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11692 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11693 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11694 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11695 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11696 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11697 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11698 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11699 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011700 {}
11701};
11702
Tobin Davisf651b502007-10-26 12:40:47 +020011703/* mute/unmute internal speaker according to the hp jack and mute state */
11704static void alc262_ultra_automute(struct hda_codec *codec)
11705{
11706 struct alc_spec *spec = codec->spec;
11707 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011708
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011709 mute = 0;
11710 /* auto-mute only when HP is used as HP */
11711 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011712 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011713 if (spec->jack_present)
11714 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011715 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011716 /* mute/unmute internal speaker */
11717 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11718 HDA_AMP_MUTE, mute);
11719 /* mute/unmute HP */
11720 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11721 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011722}
11723
11724/* unsolicited event for HP jack sensing */
11725static void alc262_ultra_unsol_event(struct hda_codec *codec,
11726 unsigned int res)
11727{
11728 if ((res >> 26) != ALC880_HP_EVENT)
11729 return;
11730 alc262_ultra_automute(codec);
11731}
11732
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011733static struct hda_input_mux alc262_ultra_capture_source = {
11734 .num_items = 2,
11735 .items = {
11736 { "Mic", 0x1 },
11737 { "Headphone", 0x7 },
11738 },
11739};
11740
11741static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11742 struct snd_ctl_elem_value *ucontrol)
11743{
11744 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11745 struct alc_spec *spec = codec->spec;
11746 int ret;
11747
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011748 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011749 if (!ret)
11750 return 0;
11751 /* reprogram the HP pin as mic or HP according to the input source */
11752 snd_hda_codec_write_cache(codec, 0x15, 0,
11753 AC_VERB_SET_PIN_WIDGET_CONTROL,
11754 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11755 alc262_ultra_automute(codec); /* mute/unmute HP */
11756 return ret;
11757}
11758
11759static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11760 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11761 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11762 {
11763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11764 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011765 .info = alc_mux_enum_info,
11766 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011767 .put = alc262_ultra_mux_enum_put,
11768 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011769 {
11770 .iface = NID_MAPPING,
11771 .name = "Capture Source",
11772 .private_value = 0x15,
11773 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011774 { } /* end */
11775};
11776
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011777/* We use two mixers depending on the output pin; 0x16 is a mono output
11778 * and thus it's bound with a different mixer.
11779 * This function returns which mixer amp should be used.
11780 */
11781static int alc262_check_volbit(hda_nid_t nid)
11782{
11783 if (!nid)
11784 return 0;
11785 else if (nid == 0x16)
11786 return 2;
11787 else
11788 return 1;
11789}
11790
11791static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11792 const char *pfx, int *vbits)
11793{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011794 unsigned long val;
11795 int vbit;
11796
11797 vbit = alc262_check_volbit(nid);
11798 if (!vbit)
11799 return 0;
11800 if (*vbits & vbit) /* a volume control for this mixer already there */
11801 return 0;
11802 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011803 if (vbit == 2)
11804 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11805 else
11806 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011807 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011808}
11809
11810static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11811 const char *pfx)
11812{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011813 unsigned long val;
11814
11815 if (!nid)
11816 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011817 if (nid == 0x16)
11818 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11819 else
11820 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011821 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011822}
11823
Kailang Yangdf694da2005-12-05 19:42:22 +010011824/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011825static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11826 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011827{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011828 const char *pfx;
11829 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011830 int err;
11831
11832 spec->multiout.num_dacs = 1; /* only use one dac */
11833 spec->multiout.dac_nids = spec->private_dac_nids;
11834 spec->multiout.dac_nids[0] = 2;
11835
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011836 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11837 pfx = "Master";
11838 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11839 pfx = "Speaker";
11840 else
11841 pfx = "Front";
11842 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11843 if (err < 0)
11844 return err;
11845 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11846 if (err < 0)
11847 return err;
11848 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11849 if (err < 0)
11850 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011851
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011852 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11853 alc262_check_volbit(cfg->speaker_pins[0]) |
11854 alc262_check_volbit(cfg->hp_pins[0]);
11855 if (vbits == 1 || vbits == 2)
11856 pfx = "Master"; /* only one mixer is used */
11857 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11858 pfx = "Speaker";
11859 else
11860 pfx = "Front";
11861 vbits = 0;
11862 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11863 if (err < 0)
11864 return err;
11865 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11866 &vbits);
11867 if (err < 0)
11868 return err;
11869 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11870 &vbits);
11871 if (err < 0)
11872 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011873 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011874}
11875
Takashi Iwai05f5f472009-08-25 13:10:18 +020011876#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010011877 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011878
11879/*
11880 * generic initialization of ADC, input mixers and output mixers
11881 */
11882static struct hda_verb alc262_volume_init_verbs[] = {
11883 /*
11884 * Unmute ADC0-2 and set the default input to mic-in
11885 */
11886 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11887 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11888 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11889 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11890 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11891 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11892
Takashi Iwaicb53c622007-08-10 17:21:45 +020011893 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011894 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011895 * Note: PASD motherboards uses the Line In 2 as the input for
11896 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011897 */
11898 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011899 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11900 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11901 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11902 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11903 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011904
11905 /*
11906 * Set up output mixers (0x0c - 0x0f)
11907 */
11908 /* set vol=0 to output mixers */
11909 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11910 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11911 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011912
Kailang Yangdf694da2005-12-05 19:42:22 +010011913 /* set up input amps for analog loopback */
11914 /* Amp Indices: DAC = 0, mixer = 1 */
11915 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11916 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11917 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11918 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11919 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11920 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11921
11922 /* FIXME: use matrix-type input source selection */
11923 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11924 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11925 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11926 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11927 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11928 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11929 /* Input mixer2 */
11930 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11931 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11932 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11933 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11934 /* Input mixer3 */
11935 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11936 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11937 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11938 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11939
11940 { }
11941};
11942
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011943static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11944 /*
11945 * Unmute ADC0-2 and set the default input to mic-in
11946 */
11947 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11948 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11949 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11950 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11951 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11952 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11953
Takashi Iwaicb53c622007-08-10 17:21:45 +020011954 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011955 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011956 * Note: PASD motherboards uses the Line In 2 as the input for
11957 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011958 */
11959 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011960 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11961 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11962 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11963 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11964 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11965 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11966 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011967
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011968 /*
11969 * Set up output mixers (0x0c - 0x0e)
11970 */
11971 /* set vol=0 to output mixers */
11972 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11973 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11974 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11975
11976 /* set up input amps for analog loopback */
11977 /* Amp Indices: DAC = 0, mixer = 1 */
11978 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11979 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11980 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11981 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11982 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11983 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11984
Takashi Iwaice875f02008-01-28 18:17:43 +010011985 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011986 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11987 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11988
11989 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11990 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11991
11992 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11993 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11994
11995 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11996 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11997 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11998 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11999 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12000
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012001 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012002 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12003 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012004 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012005 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12006 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12007
12008
12009 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012010 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12011 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012012 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012013 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12014 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12015 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12016 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12017 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12018 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12019 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12020 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012021 /* Input mixer2 */
12022 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012023 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12024 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12025 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12026 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12027 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12028 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12029 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12030 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012031 /* Input mixer3 */
12032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012033 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12034 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12036 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12037 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12038 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12039 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12040 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012041
Takashi Iwaice875f02008-01-28 18:17:43 +010012042 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12043
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012044 { }
12045};
12046
Kailang Yangcd7509a2007-01-26 18:33:17 +010012047static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12048 /*
12049 * Unmute ADC0-2 and set the default input to mic-in
12050 */
12051 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12052 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12053 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12054 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12055 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12056 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12057
Takashi Iwaicb53c622007-08-10 17:21:45 +020012058 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012059 * mixer widget
12060 * Note: PASD motherboards uses the Line In 2 as the input for front
12061 * panel mic (mic 2)
12062 */
12063 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012064 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12065 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12066 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12067 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12068 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12069 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12070 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12071 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012072 /*
12073 * Set up output mixers (0x0c - 0x0e)
12074 */
12075 /* set vol=0 to output mixers */
12076 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12077 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12078 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12079
12080 /* set up input amps for analog loopback */
12081 /* Amp Indices: DAC = 0, mixer = 1 */
12082 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12083 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12084 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12085 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12086 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12087 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12088
12089
12090 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12091 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12092 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12093 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12094 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12095 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12096 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12097
12098 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12099 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12100
12101 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12102 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12103
12104 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12105 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12106 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12107 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12108 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12109 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12110
12111 /* FIXME: use matrix-type input source selection */
12112 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12113 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12114 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12115 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12116 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12117 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12118 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12119 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12120 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12121 /* Input mixer2 */
12122 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12123 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12124 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12125 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12126 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12127 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12128 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12129 /* Input mixer3 */
12130 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12131 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12132 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12133 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12134 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12135 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12136 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12137
Takashi Iwaice875f02008-01-28 18:17:43 +010012138 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12139
Kailang Yangcd7509a2007-01-26 18:33:17 +010012140 { }
12141};
12142
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012143static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12144
12145 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12146 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12147 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12148
12149 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12150 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12151 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12152 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12153
12154 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12155 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12156 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12157 {}
12158};
12159
12160
Takashi Iwaicb53c622007-08-10 17:21:45 +020012161#ifdef CONFIG_SND_HDA_POWER_SAVE
12162#define alc262_loopbacks alc880_loopbacks
12163#endif
12164
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012165/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012166#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12167#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12168#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12169#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12170
12171/*
12172 * BIOS auto configuration
12173 */
12174static int alc262_parse_auto_config(struct hda_codec *codec)
12175{
12176 struct alc_spec *spec = codec->spec;
12177 int err;
12178 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12179
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012180 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12181 alc262_ignore);
12182 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012183 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012184 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012185 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012186 spec->multiout.max_channels = 2;
12187 spec->no_analog = 1;
12188 goto dig_only;
12189 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012190 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012191 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012192 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12193 if (err < 0)
12194 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012195 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012196 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012197 return err;
12198
12199 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12200
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012201 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012202 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012203
Takashi Iwai603c4012008-07-30 15:01:44 +020012204 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012205 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012206
Takashi Iwaid88897e2008-10-31 15:01:37 +010012207 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012208 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012209 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012210
Takashi Iwai776e1842007-08-29 15:07:11 +020012211 err = alc_auto_add_mic_boost(codec);
12212 if (err < 0)
12213 return err;
12214
Kailang Yang6227cdc2010-02-25 08:36:52 +010012215 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012216
Kailang Yangdf694da2005-12-05 19:42:22 +010012217 return 1;
12218}
12219
12220#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12221#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12222#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012223#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012224
12225
12226/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012227static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012228{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012229 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012230 alc262_auto_init_multi_out(codec);
12231 alc262_auto_init_hp_out(codec);
12232 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012233 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012234 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012235 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012236 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012237}
12238
12239/*
12240 * configuration and preset
12241 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012242static const char *alc262_models[ALC262_MODEL_LAST] = {
12243 [ALC262_BASIC] = "basic",
12244 [ALC262_HIPPO] = "hippo",
12245 [ALC262_HIPPO_1] = "hippo_1",
12246 [ALC262_FUJITSU] = "fujitsu",
12247 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012248 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012249 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012250 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012251 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012252 [ALC262_BENQ_T31] = "benq-t31",
12253 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012254 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012255 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012256 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012257 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012258 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012259 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012260 [ALC262_AUTO] = "auto",
12261};
12262
12263static struct snd_pci_quirk alc262_cfg_tbl[] = {
12264 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012265 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012266 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12267 ALC262_HP_BPC),
12268 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12269 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012270 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12271 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012272 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012273 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012274 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012275 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012276 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012277 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012278 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012279 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012280 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12281 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12282 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012283 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12284 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012285 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012286 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012287 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012288 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012289 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012290 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012291 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012292 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012293#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012294 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12295 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012296#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012297 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012298 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012299 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012300 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012301 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012302 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012303 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12304 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012305 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012306 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012307 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012308 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012309 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012310 {}
12311};
12312
12313static struct alc_config_preset alc262_presets[] = {
12314 [ALC262_BASIC] = {
12315 .mixers = { alc262_base_mixer },
12316 .init_verbs = { alc262_init_verbs },
12317 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12318 .dac_nids = alc262_dac_nids,
12319 .hp_nid = 0x03,
12320 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12321 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012322 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012323 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012324 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012325 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012326 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012327 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12328 .dac_nids = alc262_dac_nids,
12329 .hp_nid = 0x03,
12330 .dig_out_nid = ALC262_DIGOUT_NID,
12331 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12332 .channel_mode = alc262_modes,
12333 .input_mux = &alc262_capture_source,
12334 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012335 .setup = alc262_hippo_setup,
12336 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012337 },
12338 [ALC262_HIPPO_1] = {
12339 .mixers = { alc262_hippo1_mixer },
12340 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12341 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12342 .dac_nids = alc262_dac_nids,
12343 .hp_nid = 0x02,
12344 .dig_out_nid = ALC262_DIGOUT_NID,
12345 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12346 .channel_mode = alc262_modes,
12347 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012348 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012349 .setup = alc262_hippo1_setup,
12350 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012351 },
Takashi Iwai834be882006-03-01 14:16:17 +010012352 [ALC262_FUJITSU] = {
12353 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012354 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12355 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012356 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12357 .dac_nids = alc262_dac_nids,
12358 .hp_nid = 0x03,
12359 .dig_out_nid = ALC262_DIGOUT_NID,
12360 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12361 .channel_mode = alc262_modes,
12362 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012363 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012364 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012365 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012366 [ALC262_HP_BPC] = {
12367 .mixers = { alc262_HP_BPC_mixer },
12368 .init_verbs = { alc262_HP_BPC_init_verbs },
12369 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12370 .dac_nids = alc262_dac_nids,
12371 .hp_nid = 0x03,
12372 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12373 .channel_mode = alc262_modes,
12374 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012375 .unsol_event = alc262_hp_bpc_unsol_event,
12376 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012377 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012378 [ALC262_HP_BPC_D7000_WF] = {
12379 .mixers = { alc262_HP_BPC_WildWest_mixer },
12380 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12381 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12382 .dac_nids = alc262_dac_nids,
12383 .hp_nid = 0x03,
12384 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12385 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012386 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012387 .unsol_event = alc262_hp_wildwest_unsol_event,
12388 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012389 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012390 [ALC262_HP_BPC_D7000_WL] = {
12391 .mixers = { alc262_HP_BPC_WildWest_mixer,
12392 alc262_HP_BPC_WildWest_option_mixer },
12393 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12394 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12395 .dac_nids = alc262_dac_nids,
12396 .hp_nid = 0x03,
12397 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12398 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012399 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012400 .unsol_event = alc262_hp_wildwest_unsol_event,
12401 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012402 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012403 [ALC262_HP_TC_T5735] = {
12404 .mixers = { alc262_hp_t5735_mixer },
12405 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12406 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12407 .dac_nids = alc262_dac_nids,
12408 .hp_nid = 0x03,
12409 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12410 .channel_mode = alc262_modes,
12411 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012412 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012413 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012414 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012415 },
12416 [ALC262_HP_RP5700] = {
12417 .mixers = { alc262_hp_rp5700_mixer },
12418 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12419 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12420 .dac_nids = alc262_dac_nids,
12421 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12422 .channel_mode = alc262_modes,
12423 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012424 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012425 [ALC262_BENQ_ED8] = {
12426 .mixers = { alc262_base_mixer },
12427 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12428 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12429 .dac_nids = alc262_dac_nids,
12430 .hp_nid = 0x03,
12431 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12432 .channel_mode = alc262_modes,
12433 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012434 },
Kailang Yang272a5272007-05-14 11:00:38 +020012435 [ALC262_SONY_ASSAMD] = {
12436 .mixers = { alc262_sony_mixer },
12437 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12438 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12439 .dac_nids = alc262_dac_nids,
12440 .hp_nid = 0x02,
12441 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12442 .channel_mode = alc262_modes,
12443 .input_mux = &alc262_capture_source,
12444 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012445 .setup = alc262_hippo_setup,
12446 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012447 },
12448 [ALC262_BENQ_T31] = {
12449 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012450 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12451 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012452 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12453 .dac_nids = alc262_dac_nids,
12454 .hp_nid = 0x03,
12455 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12456 .channel_mode = alc262_modes,
12457 .input_mux = &alc262_capture_source,
12458 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012459 .setup = alc262_hippo_setup,
12460 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012461 },
Tobin Davisf651b502007-10-26 12:40:47 +020012462 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012463 .mixers = { alc262_ultra_mixer },
12464 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012465 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012466 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12467 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012468 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12469 .channel_mode = alc262_modes,
12470 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012471 .adc_nids = alc262_adc_nids, /* ADC0 */
12472 .capsrc_nids = alc262_capsrc_nids,
12473 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012474 .unsol_event = alc262_ultra_unsol_event,
12475 .init_hook = alc262_ultra_automute,
12476 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012477 [ALC262_LENOVO_3000] = {
12478 .mixers = { alc262_lenovo_3000_mixer },
12479 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012480 alc262_lenovo_3000_unsol_verbs,
12481 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012482 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12483 .dac_nids = alc262_dac_nids,
12484 .hp_nid = 0x03,
12485 .dig_out_nid = ALC262_DIGOUT_NID,
12486 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12487 .channel_mode = alc262_modes,
12488 .input_mux = &alc262_fujitsu_capture_source,
12489 .unsol_event = alc262_lenovo_3000_unsol_event,
12490 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012491 [ALC262_NEC] = {
12492 .mixers = { alc262_nec_mixer },
12493 .init_verbs = { alc262_nec_verbs },
12494 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12495 .dac_nids = alc262_dac_nids,
12496 .hp_nid = 0x03,
12497 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12498 .channel_mode = alc262_modes,
12499 .input_mux = &alc262_capture_source,
12500 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012501 [ALC262_TOSHIBA_S06] = {
12502 .mixers = { alc262_toshiba_s06_mixer },
12503 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12504 alc262_eapd_verbs },
12505 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12506 .capsrc_nids = alc262_dmic_capsrc_nids,
12507 .dac_nids = alc262_dac_nids,
12508 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012509 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012510 .dig_out_nid = ALC262_DIGOUT_NID,
12511 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12512 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012513 .unsol_event = alc_sku_unsol_event,
12514 .setup = alc262_toshiba_s06_setup,
12515 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012516 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012517 [ALC262_TOSHIBA_RX1] = {
12518 .mixers = { alc262_toshiba_rx1_mixer },
12519 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12520 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12521 .dac_nids = alc262_dac_nids,
12522 .hp_nid = 0x03,
12523 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12524 .channel_mode = alc262_modes,
12525 .input_mux = &alc262_capture_source,
12526 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012527 .setup = alc262_hippo_setup,
12528 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012529 },
Tony Vroonba340e82009-02-02 19:01:30 +000012530 [ALC262_TYAN] = {
12531 .mixers = { alc262_tyan_mixer },
12532 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12533 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12534 .dac_nids = alc262_dac_nids,
12535 .hp_nid = 0x02,
12536 .dig_out_nid = ALC262_DIGOUT_NID,
12537 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12538 .channel_mode = alc262_modes,
12539 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012540 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012541 .setup = alc262_tyan_setup,
12542 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012543 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012544};
12545
12546static int patch_alc262(struct hda_codec *codec)
12547{
12548 struct alc_spec *spec;
12549 int board_config;
12550 int err;
12551
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012552 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012553 if (spec == NULL)
12554 return -ENOMEM;
12555
12556 codec->spec = spec;
12557#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012558 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12559 * under-run
12560 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012561 {
12562 int tmp;
12563 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12564 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12565 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12566 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12567 }
12568#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012569 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012570
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012571 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12572
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012573 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12574 alc262_models,
12575 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012576
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012577 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012578 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12579 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012580 board_config = ALC262_AUTO;
12581 }
12582
12583 if (board_config == ALC262_AUTO) {
12584 /* automatic parse from the BIOS config */
12585 err = alc262_parse_auto_config(codec);
12586 if (err < 0) {
12587 alc_free(codec);
12588 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012589 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012590 printk(KERN_INFO
12591 "hda_codec: Cannot set up configuration "
12592 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012593 board_config = ALC262_BASIC;
12594 }
12595 }
12596
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012597 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012598 err = snd_hda_attach_beep_device(codec, 0x1);
12599 if (err < 0) {
12600 alc_free(codec);
12601 return err;
12602 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012603 }
12604
Kailang Yangdf694da2005-12-05 19:42:22 +010012605 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012606 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012607
Kailang Yangdf694da2005-12-05 19:42:22 +010012608 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12609 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012610
Kailang Yangdf694da2005-12-05 19:42:22 +010012611 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12612 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12613
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012614 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012615 int i;
12616 /* check whether the digital-mic has to be supported */
12617 for (i = 0; i < spec->input_mux->num_items; i++) {
12618 if (spec->input_mux->items[i].index >= 9)
12619 break;
12620 }
12621 if (i < spec->input_mux->num_items) {
12622 /* use only ADC0 */
12623 spec->adc_nids = alc262_dmic_adc_nids;
12624 spec->num_adc_nids = 1;
12625 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012626 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012627 /* all analog inputs */
12628 /* check whether NID 0x07 is valid */
12629 unsigned int wcap = get_wcaps(codec, 0x07);
12630
12631 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012632 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012633 if (wcap != AC_WID_AUD_IN) {
12634 spec->adc_nids = alc262_adc_nids_alt;
12635 spec->num_adc_nids =
12636 ARRAY_SIZE(alc262_adc_nids_alt);
12637 spec->capsrc_nids = alc262_capsrc_nids_alt;
12638 } else {
12639 spec->adc_nids = alc262_adc_nids;
12640 spec->num_adc_nids =
12641 ARRAY_SIZE(alc262_adc_nids);
12642 spec->capsrc_nids = alc262_capsrc_nids;
12643 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012644 }
12645 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012646 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012647 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012648 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012649 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012650
Takashi Iwai2134ea42008-01-10 16:53:55 +010012651 spec->vmaster_nid = 0x0c;
12652
Kailang Yangdf694da2005-12-05 19:42:22 +010012653 codec->patch_ops = alc_patch_ops;
12654 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012655 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012656#ifdef CONFIG_SND_HDA_POWER_SAVE
12657 if (!spec->loopback.amplist)
12658 spec->loopback.amplist = alc262_loopbacks;
12659#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012660
Kailang Yangdf694da2005-12-05 19:42:22 +010012661 return 0;
12662}
12663
Kailang Yangdf694da2005-12-05 19:42:22 +010012664/*
Kailang Yanga361d842007-06-05 12:30:55 +020012665 * ALC268 channel source setting (2 channel)
12666 */
12667#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12668#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012669
Kailang Yanga361d842007-06-05 12:30:55 +020012670static hda_nid_t alc268_dac_nids[2] = {
12671 /* front, hp */
12672 0x02, 0x03
12673};
12674
12675static hda_nid_t alc268_adc_nids[2] = {
12676 /* ADC0-1 */
12677 0x08, 0x07
12678};
12679
12680static hda_nid_t alc268_adc_nids_alt[1] = {
12681 /* ADC0 */
12682 0x08
12683};
12684
Takashi Iwaie1406342008-02-11 18:32:32 +010012685static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12686
Kailang Yanga361d842007-06-05 12:30:55 +020012687static struct snd_kcontrol_new alc268_base_mixer[] = {
12688 /* output mixer control */
12689 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12690 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12691 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12692 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012693 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12694 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12695 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012696 { }
12697};
12698
Takashi Iwai42171c12009-05-08 14:11:43 +020012699static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12700 /* output mixer control */
12701 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12702 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12703 ALC262_HIPPO_MASTER_SWITCH,
12704 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12705 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12706 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12707 { }
12708};
12709
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012710/* bind Beep switches of both NID 0x0f and 0x10 */
12711static struct hda_bind_ctls alc268_bind_beep_sw = {
12712 .ops = &snd_hda_bind_sw,
12713 .values = {
12714 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12715 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12716 0
12717 },
12718};
12719
12720static struct snd_kcontrol_new alc268_beep_mixer[] = {
12721 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12722 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12723 { }
12724};
12725
Kailang Yangd1a991a2007-08-15 16:21:59 +020012726static struct hda_verb alc268_eapd_verbs[] = {
12727 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12728 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12729 { }
12730};
12731
Takashi Iwaid2738092007-08-16 14:59:45 +020012732/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012733static struct hda_verb alc268_toshiba_verbs[] = {
12734 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12735 { } /* end */
12736};
12737
12738/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012739/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012740static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12741 .ops = &snd_hda_bind_vol,
12742 .values = {
12743 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12744 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12745 0
12746 },
12747};
12748
Takashi Iwai889c4392007-08-23 18:56:52 +020012749/* mute/unmute internal speaker according to the hp jack and mute state */
12750static void alc268_acer_automute(struct hda_codec *codec, int force)
12751{
12752 struct alc_spec *spec = codec->spec;
12753 unsigned int mute;
12754
12755 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012756 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012757 spec->sense_updated = 1;
12758 }
12759 if (spec->jack_present)
12760 mute = HDA_AMP_MUTE; /* mute internal speaker */
12761 else /* unmute internal speaker if necessary */
12762 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12763 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12764 HDA_AMP_MUTE, mute);
12765}
12766
12767
12768/* bind hp and internal speaker mute (with plug check) */
12769static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12770 struct snd_ctl_elem_value *ucontrol)
12771{
12772 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12773 long *valp = ucontrol->value.integer.value;
12774 int change;
12775
Takashi Iwai8de56b72009-07-24 16:51:47 +020012776 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012777 if (change)
12778 alc268_acer_automute(codec, 0);
12779 return change;
12780}
Takashi Iwaid2738092007-08-16 14:59:45 +020012781
Kailang Yang8ef355d2008-08-26 13:10:22 +020012782static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12783 /* output mixer control */
12784 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12785 {
12786 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12787 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012788 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012789 .info = snd_hda_mixer_amp_switch_info,
12790 .get = snd_hda_mixer_amp_switch_get,
12791 .put = alc268_acer_master_sw_put,
12792 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12793 },
12794 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12795 { }
12796};
12797
Takashi Iwaid2738092007-08-16 14:59:45 +020012798static struct snd_kcontrol_new alc268_acer_mixer[] = {
12799 /* output mixer control */
12800 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12801 {
12802 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12803 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012804 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020012805 .info = snd_hda_mixer_amp_switch_info,
12806 .get = snd_hda_mixer_amp_switch_get,
12807 .put = alc268_acer_master_sw_put,
12808 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12809 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012810 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12811 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12812 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012813 { }
12814};
12815
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012816static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12817 /* output mixer control */
12818 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12819 {
12820 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12821 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012822 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012823 .info = snd_hda_mixer_amp_switch_info,
12824 .get = snd_hda_mixer_amp_switch_get,
12825 .put = alc268_acer_master_sw_put,
12826 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12827 },
12828 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12829 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12830 { }
12831};
12832
Kailang Yang8ef355d2008-08-26 13:10:22 +020012833static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12834 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12835 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12836 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12837 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12838 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12839 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12840 { }
12841};
12842
Takashi Iwaid2738092007-08-16 14:59:45 +020012843static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012844 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12845 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012846 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12847 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012848 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12849 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012850 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12851 { }
12852};
12853
12854/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012855#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012856#define alc268_toshiba_setup alc262_hippo_setup
12857#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012858
12859static void alc268_acer_unsol_event(struct hda_codec *codec,
12860 unsigned int res)
12861{
Takashi Iwai889c4392007-08-23 18:56:52 +020012862 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012863 return;
12864 alc268_acer_automute(codec, 1);
12865}
12866
Takashi Iwai889c4392007-08-23 18:56:52 +020012867static void alc268_acer_init_hook(struct hda_codec *codec)
12868{
12869 alc268_acer_automute(codec, 1);
12870}
12871
Kailang Yang8ef355d2008-08-26 13:10:22 +020012872/* toggle speaker-output according to the hp-jack state */
12873static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12874{
12875 unsigned int present;
12876 unsigned char bits;
12877
Wu Fengguang864f92b2009-11-18 12:38:02 +080012878 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012879 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012880 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012881 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012882 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012883 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012884}
12885
Kailang Yang8ef355d2008-08-26 13:10:22 +020012886static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12887 unsigned int res)
12888{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012889 switch (res >> 26) {
12890 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012891 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012892 break;
12893 case ALC880_MIC_EVENT:
12894 alc_mic_automute(codec);
12895 break;
12896 }
12897}
12898
12899static void alc268_acer_lc_setup(struct hda_codec *codec)
12900{
12901 struct alc_spec *spec = codec->spec;
12902 spec->ext_mic.pin = 0x18;
12903 spec->ext_mic.mux_idx = 0;
12904 spec->int_mic.pin = 0x12;
12905 spec->int_mic.mux_idx = 6;
12906 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012907}
12908
12909static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12910{
12911 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012912 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012913}
12914
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012915static struct snd_kcontrol_new alc268_dell_mixer[] = {
12916 /* output mixer control */
12917 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12918 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12919 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12920 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12921 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12922 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12923 { }
12924};
12925
12926static struct hda_verb alc268_dell_verbs[] = {
12927 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12928 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12929 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012930 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012931 { }
12932};
12933
12934/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012935static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012936{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012937 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012938
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012939 spec->autocfg.hp_pins[0] = 0x15;
12940 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012941 spec->ext_mic.pin = 0x18;
12942 spec->ext_mic.mux_idx = 0;
12943 spec->int_mic.pin = 0x19;
12944 spec->int_mic.mux_idx = 1;
12945 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012946}
12947
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012948static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12949 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12950 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12951 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12952 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12953 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12954 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12955 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12956 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12957 { }
12958};
12959
12960static struct hda_verb alc267_quanta_il1_verbs[] = {
12961 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12962 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12963 { }
12964};
12965
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012966static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012967{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012968 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012969 spec->autocfg.hp_pins[0] = 0x15;
12970 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012971 spec->ext_mic.pin = 0x18;
12972 spec->ext_mic.mux_idx = 0;
12973 spec->int_mic.pin = 0x19;
12974 spec->int_mic.mux_idx = 1;
12975 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012976}
12977
Kailang Yanga361d842007-06-05 12:30:55 +020012978/*
12979 * generic initialization of ADC, input mixers and output mixers
12980 */
12981static struct hda_verb alc268_base_init_verbs[] = {
12982 /* Unmute DAC0-1 and set vol = 0 */
12983 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012984 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012985
12986 /*
12987 * Set up output mixers (0x0c - 0x0e)
12988 */
12989 /* set vol=0 to output mixers */
12990 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012991 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12992
12993 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12994 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12995
12996 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12997 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12998 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12999 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13000 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13001 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13002 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13003 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13004
13005 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13006 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13007 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13008 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013009 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013010
13011 /* set PCBEEP vol = 0, mute connections */
13012 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13013 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13014 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013015
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013016 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013017
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013018 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13019 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13020 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13021 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013022
Kailang Yanga361d842007-06-05 12:30:55 +020013023 { }
13024};
13025
13026/*
13027 * generic initialization of ADC, input mixers and output mixers
13028 */
13029static struct hda_verb alc268_volume_init_verbs[] = {
13030 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013031 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13032 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013033
13034 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13035 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13036 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13037 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13038 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13039
Kailang Yanga361d842007-06-05 12:30:55 +020013040 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013041 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13042 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13043
13044 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013045 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013046
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013047 /* set PCBEEP vol = 0, mute connections */
13048 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13049 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13050 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013051
13052 { }
13053};
13054
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013055static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13056 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13057 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13058 { } /* end */
13059};
13060
Kailang Yanga361d842007-06-05 12:30:55 +020013061static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13062 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13063 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013064 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013065 { } /* end */
13066};
13067
13068static struct snd_kcontrol_new alc268_capture_mixer[] = {
13069 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13070 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13071 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13072 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013073 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013074 { } /* end */
13075};
13076
13077static struct hda_input_mux alc268_capture_source = {
13078 .num_items = 4,
13079 .items = {
13080 { "Mic", 0x0 },
13081 { "Front Mic", 0x1 },
13082 { "Line", 0x2 },
13083 { "CD", 0x3 },
13084 },
13085};
13086
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013087static struct hda_input_mux alc268_acer_capture_source = {
13088 .num_items = 3,
13089 .items = {
13090 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013091 { "Internal Mic", 0x1 },
13092 { "Line", 0x2 },
13093 },
13094};
13095
13096static struct hda_input_mux alc268_acer_dmic_capture_source = {
13097 .num_items = 3,
13098 .items = {
13099 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013100 { "Internal Mic", 0x6 },
13101 { "Line", 0x2 },
13102 },
13103};
13104
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013105#ifdef CONFIG_SND_DEBUG
13106static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013107 /* Volume widgets */
13108 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13109 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13110 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13111 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13112 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13113 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13114 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13115 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13116 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13117 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13118 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13119 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13120 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013121 /* The below appears problematic on some hardwares */
13122 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013123 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13124 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13125 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13126 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13127
13128 /* Modes for retasking pin widgets */
13129 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13130 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13131 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13132 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13133
13134 /* Controls for GPIO pins, assuming they are configured as outputs */
13135 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13136 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13137 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13138 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13139
13140 /* Switches to allow the digital SPDIF output pin to be enabled.
13141 * The ALC268 does not have an SPDIF input.
13142 */
13143 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13144
13145 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13146 * this output to turn on an external amplifier.
13147 */
13148 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13149 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13150
13151 { } /* end */
13152};
13153#endif
13154
Kailang Yanga361d842007-06-05 12:30:55 +020013155/* create input playback/capture controls for the given pin */
13156static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13157 const char *ctlname, int idx)
13158{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013159 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013160 int err;
13161
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013162 switch (nid) {
13163 case 0x14:
13164 case 0x16:
13165 dac = 0x02;
13166 break;
13167 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013168 case 0x1a: /* ALC259/269 only */
13169 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013170 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013171 dac = 0x03;
13172 break;
13173 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013174 snd_printd(KERN_WARNING "hda_codec: "
13175 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013176 return 0;
13177 }
13178 if (spec->multiout.dac_nids[0] != dac &&
13179 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013180 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013181 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013182 HDA_OUTPUT));
13183 if (err < 0)
13184 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013185 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13186 }
13187
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013188 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013189 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013190 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013191 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013192 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013193 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013194 if (err < 0)
13195 return err;
13196 return 0;
13197}
13198
13199/* add playback controls from the parsed DAC table */
13200static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13201 const struct auto_pin_cfg *cfg)
13202{
13203 hda_nid_t nid;
13204 int err;
13205
Kailang Yanga361d842007-06-05 12:30:55 +020013206 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013207
13208 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013209 if (nid) {
13210 const char *name;
13211 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13212 name = "Speaker";
13213 else
13214 name = "Front";
13215 err = alc268_new_analog_output(spec, nid, name, 0);
13216 if (err < 0)
13217 return err;
13218 }
Kailang Yanga361d842007-06-05 12:30:55 +020013219
13220 nid = cfg->speaker_pins[0];
13221 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013222 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013223 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13224 if (err < 0)
13225 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013226 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013227 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13228 if (err < 0)
13229 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013230 }
13231 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013232 if (nid) {
13233 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13234 if (err < 0)
13235 return err;
13236 }
Kailang Yanga361d842007-06-05 12:30:55 +020013237
13238 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13239 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013240 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013241 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013242 if (err < 0)
13243 return err;
13244 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013245 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013246}
13247
13248/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013249static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013250 const struct auto_pin_cfg *cfg)
13251{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013252 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013253}
13254
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013255static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13256 hda_nid_t nid, int pin_type)
13257{
13258 int idx;
13259
13260 alc_set_pin_output(codec, nid, pin_type);
13261 if (nid == 0x14 || nid == 0x16)
13262 idx = 0;
13263 else
13264 idx = 1;
13265 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13266}
13267
13268static void alc268_auto_init_multi_out(struct hda_codec *codec)
13269{
13270 struct alc_spec *spec = codec->spec;
13271 hda_nid_t nid = spec->autocfg.line_out_pins[0];
13272 if (nid) {
13273 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13274 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13275 }
13276}
13277
13278static void alc268_auto_init_hp_out(struct hda_codec *codec)
13279{
13280 struct alc_spec *spec = codec->spec;
13281 hda_nid_t pin;
13282
13283 pin = spec->autocfg.hp_pins[0];
13284 if (pin)
13285 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
13286 pin = spec->autocfg.speaker_pins[0];
13287 if (pin)
13288 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
13289}
13290
Kailang Yanga361d842007-06-05 12:30:55 +020013291static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13292{
13293 struct alc_spec *spec = codec->spec;
13294 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13295 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13296 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13297 unsigned int dac_vol1, dac_vol2;
13298
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013299 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013300 snd_hda_codec_write(codec, speaker_nid, 0,
13301 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013302 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013303 snd_hda_codec_write(codec, 0x0f, 0,
13304 AC_VERB_SET_AMP_GAIN_MUTE,
13305 AMP_IN_UNMUTE(1));
13306 snd_hda_codec_write(codec, 0x10, 0,
13307 AC_VERB_SET_AMP_GAIN_MUTE,
13308 AMP_IN_UNMUTE(1));
13309 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013310 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013311 snd_hda_codec_write(codec, 0x0f, 0,
13312 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13313 snd_hda_codec_write(codec, 0x10, 0,
13314 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13315 }
13316
13317 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013318 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013319 dac_vol2 = AMP_OUT_ZERO;
13320 else if (line_nid == 0x15)
13321 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013322 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013323 dac_vol2 = AMP_OUT_ZERO;
13324 else if (hp_nid == 0x15)
13325 dac_vol1 = AMP_OUT_ZERO;
13326 if (line_nid != 0x16 || hp_nid != 0x16 ||
13327 spec->autocfg.line_out_pins[1] != 0x16 ||
13328 spec->autocfg.line_out_pins[2] != 0x16)
13329 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13330
13331 snd_hda_codec_write(codec, 0x02, 0,
13332 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13333 snd_hda_codec_write(codec, 0x03, 0,
13334 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13335}
13336
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013337/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013338#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13339#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013340#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013341#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13342
13343/*
13344 * BIOS auto configuration
13345 */
13346static int alc268_parse_auto_config(struct hda_codec *codec)
13347{
13348 struct alc_spec *spec = codec->spec;
13349 int err;
13350 static hda_nid_t alc268_ignore[] = { 0 };
13351
13352 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13353 alc268_ignore);
13354 if (err < 0)
13355 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013356 if (!spec->autocfg.line_outs) {
13357 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13358 spec->multiout.max_channels = 2;
13359 spec->no_analog = 1;
13360 goto dig_only;
13361 }
Kailang Yanga361d842007-06-05 12:30:55 +020013362 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013363 }
Kailang Yanga361d842007-06-05 12:30:55 +020013364 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13365 if (err < 0)
13366 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013367 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013368 if (err < 0)
13369 return err;
13370
13371 spec->multiout.max_channels = 2;
13372
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013373 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013374 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013375 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013376 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013377 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013378
Takashi Iwai892981f2009-03-02 08:04:35 +010013379 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013380 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013381
Takashi Iwaid88897e2008-10-31 15:01:37 +010013382 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013383 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013384 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013385
Takashi Iwai776e1842007-08-29 15:07:11 +020013386 err = alc_auto_add_mic_boost(codec);
13387 if (err < 0)
13388 return err;
13389
Kailang Yang6227cdc2010-02-25 08:36:52 +010013390 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013391
Kailang Yanga361d842007-06-05 12:30:55 +020013392 return 1;
13393}
13394
Kailang Yanga361d842007-06-05 12:30:55 +020013395#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13396
13397/* init callback for auto-configuration model -- overriding the default init */
13398static void alc268_auto_init(struct hda_codec *codec)
13399{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013400 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013401 alc268_auto_init_multi_out(codec);
13402 alc268_auto_init_hp_out(codec);
13403 alc268_auto_init_mono_speaker_out(codec);
13404 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013405 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013406 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013407 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013408}
13409
13410/*
13411 * configuration and preset
13412 */
13413static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013414 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013415 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013416 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013417 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013418 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013419 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013420 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013421 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013422#ifdef CONFIG_SND_DEBUG
13423 [ALC268_TEST] = "test",
13424#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013425 [ALC268_AUTO] = "auto",
13426};
13427
13428static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013429 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013430 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013431 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013432 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013433 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013434 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13435 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013436 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013437 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13438 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013439 /* almost compatible with toshiba but with optional digital outs;
13440 * auto-probing seems working fine
13441 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013442 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013443 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013444 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013445 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013446 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013447 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013448 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013449 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020013450 {}
13451};
13452
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013453/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13454static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13455 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13456 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13457 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13458 ALC268_TOSHIBA),
13459 {}
13460};
13461
Kailang Yanga361d842007-06-05 12:30:55 +020013462static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013463 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013464 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13465 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013466 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13467 alc267_quanta_il1_verbs },
13468 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13469 .dac_nids = alc268_dac_nids,
13470 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13471 .adc_nids = alc268_adc_nids_alt,
13472 .hp_nid = 0x03,
13473 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13474 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013475 .unsol_event = alc_sku_unsol_event,
13476 .setup = alc267_quanta_il1_setup,
13477 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013478 },
Kailang Yanga361d842007-06-05 12:30:55 +020013479 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013480 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13481 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013482 .init_verbs = { alc268_base_init_verbs },
13483 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13484 .dac_nids = alc268_dac_nids,
13485 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13486 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013487 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013488 .hp_nid = 0x03,
13489 .dig_out_nid = ALC268_DIGOUT_NID,
13490 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13491 .channel_mode = alc268_modes,
13492 .input_mux = &alc268_capture_source,
13493 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013494 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013495 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013496 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013497 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13498 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013499 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13500 .dac_nids = alc268_dac_nids,
13501 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13502 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013503 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013504 .hp_nid = 0x03,
13505 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13506 .channel_mode = alc268_modes,
13507 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013508 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013509 .setup = alc268_toshiba_setup,
13510 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013511 },
13512 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013513 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013514 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013515 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13516 alc268_acer_verbs },
13517 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13518 .dac_nids = alc268_dac_nids,
13519 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13520 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013521 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013522 .hp_nid = 0x02,
13523 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13524 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013525 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013526 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013527 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013528 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013529 [ALC268_ACER_DMIC] = {
13530 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13531 alc268_beep_mixer },
13532 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13533 alc268_acer_verbs },
13534 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13535 .dac_nids = alc268_dac_nids,
13536 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13537 .adc_nids = alc268_adc_nids_alt,
13538 .capsrc_nids = alc268_capsrc_nids,
13539 .hp_nid = 0x02,
13540 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13541 .channel_mode = alc268_modes,
13542 .input_mux = &alc268_acer_dmic_capture_source,
13543 .unsol_event = alc268_acer_unsol_event,
13544 .init_hook = alc268_acer_init_hook,
13545 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013546 [ALC268_ACER_ASPIRE_ONE] = {
13547 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013548 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013549 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013550 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13551 alc268_acer_aspire_one_verbs },
13552 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13553 .dac_nids = alc268_dac_nids,
13554 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13555 .adc_nids = alc268_adc_nids_alt,
13556 .capsrc_nids = alc268_capsrc_nids,
13557 .hp_nid = 0x03,
13558 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13559 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013560 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013561 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013562 .init_hook = alc268_acer_lc_init_hook,
13563 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013564 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013565 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13566 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013567 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13568 alc268_dell_verbs },
13569 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13570 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013571 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13572 .adc_nids = alc268_adc_nids_alt,
13573 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013574 .hp_nid = 0x02,
13575 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13576 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013577 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013578 .setup = alc268_dell_setup,
13579 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013580 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013581 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013582 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13583 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013584 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13585 alc268_toshiba_verbs },
13586 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13587 .dac_nids = alc268_dac_nids,
13588 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13589 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013590 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013591 .hp_nid = 0x03,
13592 .dig_out_nid = ALC268_DIGOUT_NID,
13593 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13594 .channel_mode = alc268_modes,
13595 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013596 .setup = alc268_toshiba_setup,
13597 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013598 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013599#ifdef CONFIG_SND_DEBUG
13600 [ALC268_TEST] = {
13601 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13602 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13603 alc268_volume_init_verbs },
13604 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13605 .dac_nids = alc268_dac_nids,
13606 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13607 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013608 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013609 .hp_nid = 0x03,
13610 .dig_out_nid = ALC268_DIGOUT_NID,
13611 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13612 .channel_mode = alc268_modes,
13613 .input_mux = &alc268_capture_source,
13614 },
13615#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013616};
13617
13618static int patch_alc268(struct hda_codec *codec)
13619{
13620 struct alc_spec *spec;
13621 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013622 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013623
Julia Lawallef86f582009-12-19 08:18:03 +010013624 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013625 if (spec == NULL)
13626 return -ENOMEM;
13627
13628 codec->spec = spec;
13629
13630 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13631 alc268_models,
13632 alc268_cfg_tbl);
13633
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013634 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13635 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013636 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013637
Kailang Yanga361d842007-06-05 12:30:55 +020013638 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013639 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13640 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013641 board_config = ALC268_AUTO;
13642 }
13643
13644 if (board_config == ALC268_AUTO) {
13645 /* automatic parse from the BIOS config */
13646 err = alc268_parse_auto_config(codec);
13647 if (err < 0) {
13648 alc_free(codec);
13649 return err;
13650 } else if (!err) {
13651 printk(KERN_INFO
13652 "hda_codec: Cannot set up configuration "
13653 "from BIOS. Using base mode...\n");
13654 board_config = ALC268_3ST;
13655 }
13656 }
13657
13658 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013659 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013660
Kailang Yanga361d842007-06-05 12:30:55 +020013661 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13662 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013663 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013664
Kailang Yanga361d842007-06-05 12:30:55 +020013665 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13666
Takashi Iwai22971e32009-02-10 11:56:44 +010013667 has_beep = 0;
13668 for (i = 0; i < spec->num_mixers; i++) {
13669 if (spec->mixers[i] == alc268_beep_mixer) {
13670 has_beep = 1;
13671 break;
13672 }
13673 }
13674
13675 if (has_beep) {
13676 err = snd_hda_attach_beep_device(codec, 0x1);
13677 if (err < 0) {
13678 alc_free(codec);
13679 return err;
13680 }
13681 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13682 /* override the amp caps for beep generator */
13683 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013684 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13685 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13686 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13687 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013688 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013689
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013690 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013691 /* check whether NID 0x07 is valid */
13692 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013693 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013694
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013695 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013696 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013697 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013698 if (spec->auto_mic ||
13699 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013700 spec->adc_nids = alc268_adc_nids_alt;
13701 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013702 if (spec->auto_mic)
13703 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013704 if (spec->auto_mic || spec->input_mux->num_items == 1)
13705 add_mixer(spec, alc268_capture_nosrc_mixer);
13706 else
13707 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013708 } else {
13709 spec->adc_nids = alc268_adc_nids;
13710 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013711 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013712 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013713 /* set default input source */
13714 for (i = 0; i < spec->num_adc_nids; i++)
13715 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13716 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013717 i < spec->num_mux_defs ?
13718 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013719 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013720 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013721
13722 spec->vmaster_nid = 0x02;
13723
Kailang Yanga361d842007-06-05 12:30:55 +020013724 codec->patch_ops = alc_patch_ops;
13725 if (board_config == ALC268_AUTO)
13726 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013727
Kailang Yanga361d842007-06-05 12:30:55 +020013728 return 0;
13729}
13730
13731/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013732 * ALC269 channel source setting (2 channel)
13733 */
13734#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13735
13736#define alc269_dac_nids alc260_dac_nids
13737
13738static hda_nid_t alc269_adc_nids[1] = {
13739 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013740 0x08,
13741};
13742
Takashi Iwaie01bf502008-08-21 16:25:07 +020013743static hda_nid_t alc269_capsrc_nids[1] = {
13744 0x23,
13745};
13746
Kailang Yang84898e82010-02-04 14:16:14 +010013747static hda_nid_t alc269vb_adc_nids[1] = {
13748 /* ADC1 */
13749 0x09,
13750};
13751
13752static hda_nid_t alc269vb_capsrc_nids[1] = {
13753 0x22,
13754};
13755
Takashi Iwai66946352010-03-29 17:21:45 +020013756static hda_nid_t alc269_adc_candidates[] = {
13757 0x08, 0x09, 0x07,
13758};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013759
Kailang Yangf6a92242007-12-13 16:52:54 +010013760#define alc269_modes alc260_modes
13761#define alc269_capture_source alc880_lg_lw_capture_source
13762
13763static struct snd_kcontrol_new alc269_base_mixer[] = {
13764 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13765 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13766 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13767 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13768 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13769 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13770 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13771 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13772 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13773 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13774 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13775 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13776 { } /* end */
13777};
13778
Kailang Yang60db6b52008-08-26 13:13:00 +020013779static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13780 /* output mixer control */
13781 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13782 {
13783 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13784 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013785 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013786 .info = snd_hda_mixer_amp_switch_info,
13787 .get = snd_hda_mixer_amp_switch_get,
13788 .put = alc268_acer_master_sw_put,
13789 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13790 },
13791 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13792 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13793 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13794 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13795 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13796 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013797 { }
13798};
13799
Tony Vroon64154832008-11-06 15:08:49 +000013800static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13801 /* output mixer control */
13802 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13803 {
13804 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13805 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013806 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013807 .info = snd_hda_mixer_amp_switch_info,
13808 .get = snd_hda_mixer_amp_switch_get,
13809 .put = alc268_acer_master_sw_put,
13810 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13811 },
13812 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13813 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13814 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13815 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13816 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13817 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13818 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13819 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13820 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013821 { }
13822};
13823
Kailang Yang84898e82010-02-04 14:16:14 +010013824static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013825 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013826 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013827 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013828 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013829 { } /* end */
13830};
13831
Kailang Yang84898e82010-02-04 14:16:14 +010013832static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
13833 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13834 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13835 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13836 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13837 { } /* end */
13838};
13839
Kailang Yangf6a92242007-12-13 16:52:54 +010013840/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010013841static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
13842 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13843 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13844 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13845 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13846 { } /* end */
13847};
13848
13849static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013850 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13851 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013852 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13853 { } /* end */
13854};
13855
Kailang Yang84898e82010-02-04 14:16:14 +010013856static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
13857 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13858 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13859 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13860 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13861 { } /* end */
13862};
13863
13864static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
13865 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13866 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13867 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13868 { } /* end */
13869};
13870
Takashi Iwai26f5df22008-11-03 17:39:46 +010013871/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013872#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013873
Kailang Yang60db6b52008-08-26 13:13:00 +020013874static struct hda_verb alc269_quanta_fl1_verbs[] = {
13875 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13876 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13877 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13878 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13879 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13880 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13881 { }
13882};
13883
Tony Vroon64154832008-11-06 15:08:49 +000013884static struct hda_verb alc269_lifebook_verbs[] = {
13885 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13886 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13887 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13888 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13889 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13890 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13891 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13892 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13893 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13894 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13895 { }
13896};
13897
Kailang Yang60db6b52008-08-26 13:13:00 +020013898/* toggle speaker-output according to the hp-jack state */
13899static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13900{
13901 unsigned int present;
13902 unsigned char bits;
13903
Wu Fengguang864f92b2009-11-18 12:38:02 +080013904 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013905 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020013906 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013907 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013908 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013909 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013910
13911 snd_hda_codec_write(codec, 0x20, 0,
13912 AC_VERB_SET_COEF_INDEX, 0x0c);
13913 snd_hda_codec_write(codec, 0x20, 0,
13914 AC_VERB_SET_PROC_COEF, 0x680);
13915
13916 snd_hda_codec_write(codec, 0x20, 0,
13917 AC_VERB_SET_COEF_INDEX, 0x0c);
13918 snd_hda_codec_write(codec, 0x20, 0,
13919 AC_VERB_SET_PROC_COEF, 0x480);
13920}
13921
Tony Vroon64154832008-11-06 15:08:49 +000013922/* toggle speaker-output according to the hp-jacks state */
13923static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13924{
13925 unsigned int present;
13926 unsigned char bits;
13927
13928 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013929 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013930
13931 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013932 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013933
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013934 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000013935 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013936 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013937 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013938 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013939
13940 snd_hda_codec_write(codec, 0x20, 0,
13941 AC_VERB_SET_COEF_INDEX, 0x0c);
13942 snd_hda_codec_write(codec, 0x20, 0,
13943 AC_VERB_SET_PROC_COEF, 0x680);
13944
13945 snd_hda_codec_write(codec, 0x20, 0,
13946 AC_VERB_SET_COEF_INDEX, 0x0c);
13947 snd_hda_codec_write(codec, 0x20, 0,
13948 AC_VERB_SET_PROC_COEF, 0x480);
13949}
13950
Tony Vroon64154832008-11-06 15:08:49 +000013951static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13952{
13953 unsigned int present_laptop;
13954 unsigned int present_dock;
13955
Wu Fengguang864f92b2009-11-18 12:38:02 +080013956 present_laptop = snd_hda_jack_detect(codec, 0x18);
13957 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013958
13959 /* Laptop mic port overrides dock mic port, design decision */
13960 if (present_dock)
13961 snd_hda_codec_write(codec, 0x23, 0,
13962 AC_VERB_SET_CONNECT_SEL, 0x3);
13963 if (present_laptop)
13964 snd_hda_codec_write(codec, 0x23, 0,
13965 AC_VERB_SET_CONNECT_SEL, 0x0);
13966 if (!present_dock && !present_laptop)
13967 snd_hda_codec_write(codec, 0x23, 0,
13968 AC_VERB_SET_CONNECT_SEL, 0x1);
13969}
13970
Kailang Yang60db6b52008-08-26 13:13:00 +020013971static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13972 unsigned int res)
13973{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013974 switch (res >> 26) {
13975 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013976 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013977 break;
13978 case ALC880_MIC_EVENT:
13979 alc_mic_automute(codec);
13980 break;
13981 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013982}
13983
Tony Vroon64154832008-11-06 15:08:49 +000013984static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13985 unsigned int res)
13986{
13987 if ((res >> 26) == ALC880_HP_EVENT)
13988 alc269_lifebook_speaker_automute(codec);
13989 if ((res >> 26) == ALC880_MIC_EVENT)
13990 alc269_lifebook_mic_autoswitch(codec);
13991}
13992
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013993static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13994{
13995 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013996 spec->autocfg.hp_pins[0] = 0x15;
13997 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013998 spec->ext_mic.pin = 0x18;
13999 spec->ext_mic.mux_idx = 0;
14000 spec->int_mic.pin = 0x19;
14001 spec->int_mic.mux_idx = 1;
14002 spec->auto_mic = 1;
14003}
14004
Kailang Yang60db6b52008-08-26 13:13:00 +020014005static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14006{
14007 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014008 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014009}
14010
Tony Vroon64154832008-11-06 15:08:49 +000014011static void alc269_lifebook_init_hook(struct hda_codec *codec)
14012{
14013 alc269_lifebook_speaker_automute(codec);
14014 alc269_lifebook_mic_autoswitch(codec);
14015}
14016
Kailang Yang84898e82010-02-04 14:16:14 +010014017static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014018 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14019 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14020 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14021 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14022 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14023 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14024 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14025 {}
14026};
14027
Kailang Yang84898e82010-02-04 14:16:14 +010014028static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014029 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14030 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14031 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14032 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14033 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14034 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14035 {}
14036};
14037
Kailang Yang84898e82010-02-04 14:16:14 +010014038static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14039 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14040 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14041 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14042 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14043 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14044 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14045 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14046 {}
14047};
14048
14049static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14050 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14051 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14052 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14053 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14054 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14055 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14056 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14057 {}
14058};
14059
Kailang Yang60db6b52008-08-26 13:13:00 +020014060/* toggle speaker-output according to the hp-jack state */
14061static void alc269_speaker_automute(struct hda_codec *codec)
14062{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014063 struct alc_spec *spec = codec->spec;
14064 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014065 unsigned int present;
14066 unsigned char bits;
14067
Kailang Yangebb83ee2009-12-17 12:23:00 +010014068 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014069 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014070 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014071 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014072 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014073 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014074}
14075
Kailang Yang60db6b52008-08-26 13:13:00 +020014076/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014077static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014078 unsigned int res)
14079{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014080 switch (res >> 26) {
14081 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014082 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014083 break;
14084 case ALC880_MIC_EVENT:
14085 alc_mic_automute(codec);
14086 break;
14087 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014088}
14089
Kailang Yang226b1ec2010-04-09 11:01:20 +020014090static void alc269_laptop_amic_setup(struct hda_codec *codec)
14091{
14092 struct alc_spec *spec = codec->spec;
14093 spec->autocfg.hp_pins[0] = 0x15;
14094 spec->autocfg.speaker_pins[0] = 0x14;
14095 spec->ext_mic.pin = 0x18;
14096 spec->ext_mic.mux_idx = 0;
14097 spec->int_mic.pin = 0x19;
14098 spec->int_mic.mux_idx = 1;
14099 spec->auto_mic = 1;
14100}
14101
Kailang Yang84898e82010-02-04 14:16:14 +010014102static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014103{
14104 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014105 spec->autocfg.hp_pins[0] = 0x15;
14106 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014107 spec->ext_mic.pin = 0x18;
14108 spec->ext_mic.mux_idx = 0;
14109 spec->int_mic.pin = 0x12;
14110 spec->int_mic.mux_idx = 5;
14111 spec->auto_mic = 1;
14112}
14113
Kailang Yang226b1ec2010-04-09 11:01:20 +020014114static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014115{
14116 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014117 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014118 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014119 spec->ext_mic.pin = 0x18;
14120 spec->ext_mic.mux_idx = 0;
14121 spec->int_mic.pin = 0x19;
14122 spec->int_mic.mux_idx = 1;
14123 spec->auto_mic = 1;
14124}
14125
Kailang Yang226b1ec2010-04-09 11:01:20 +020014126static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14127{
14128 struct alc_spec *spec = codec->spec;
14129 spec->autocfg.hp_pins[0] = 0x21;
14130 spec->autocfg.speaker_pins[0] = 0x14;
14131 spec->ext_mic.pin = 0x18;
14132 spec->ext_mic.mux_idx = 0;
14133 spec->int_mic.pin = 0x12;
14134 spec->int_mic.mux_idx = 6;
14135 spec->auto_mic = 1;
14136}
14137
Kailang Yang84898e82010-02-04 14:16:14 +010014138static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014139{
14140 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014141 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014142}
14143
Kailang Yangf6a92242007-12-13 16:52:54 +010014144/*
14145 * generic initialization of ADC, input mixers and output mixers
14146 */
14147static struct hda_verb alc269_init_verbs[] = {
14148 /*
14149 * Unmute ADC0 and set the default input to mic-in
14150 */
Kailang Yang84898e82010-02-04 14:16:14 +010014151 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014152
14153 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014154 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014155 */
14156 /* set vol=0 to output mixers */
14157 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14158 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14159
14160 /* set up input amps for analog loopback */
14161 /* Amp Indices: DAC = 0, mixer = 1 */
14162 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14163 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14164 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14165 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14166 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14167 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14168
14169 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14170 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14171 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14172 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14173 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14174 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14175 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14176
14177 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14178 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014179
Kailang Yang84898e82010-02-04 14:16:14 +010014180 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014181 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14182 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014183 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014184
14185 /* set EAPD */
14186 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014187 { }
14188};
14189
14190static struct hda_verb alc269vb_init_verbs[] = {
14191 /*
14192 * Unmute ADC0 and set the default input to mic-in
14193 */
14194 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14195
14196 /*
14197 * Set up output mixers (0x02 - 0x03)
14198 */
14199 /* set vol=0 to output mixers */
14200 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14201 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14202
14203 /* set up input amps for analog loopback */
14204 /* Amp Indices: DAC = 0, mixer = 1 */
14205 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14206 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14207 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14208 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14209 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14210 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14211
14212 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14213 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14214 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14215 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14216 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14217 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14218 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14219
14220 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14221 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14222
14223 /* FIXME: use Mux-type input source selection */
14224 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14225 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14226 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14227
14228 /* set EAPD */
14229 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014230 { }
14231};
14232
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014233#define alc269_auto_create_multi_out_ctls \
14234 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014235#define alc269_auto_create_input_ctls \
14236 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014237
14238#ifdef CONFIG_SND_HDA_POWER_SAVE
14239#define alc269_loopbacks alc880_loopbacks
14240#endif
14241
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014242/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014243#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14244#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14245#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14246#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14247
Takashi Iwaif03d3112009-03-05 14:18:16 +010014248static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14249 .substreams = 1,
14250 .channels_min = 2,
14251 .channels_max = 8,
14252 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14253 /* NID is set in alc_build_pcms */
14254 .ops = {
14255 .open = alc880_playback_pcm_open,
14256 .prepare = alc880_playback_pcm_prepare,
14257 .cleanup = alc880_playback_pcm_cleanup
14258 },
14259};
14260
14261static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14262 .substreams = 1,
14263 .channels_min = 2,
14264 .channels_max = 2,
14265 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14266 /* NID is set in alc_build_pcms */
14267};
14268
Takashi Iwaiad358792010-03-30 18:00:59 +020014269#ifdef CONFIG_SND_HDA_POWER_SAVE
14270static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14271{
14272 switch (codec->subsystem_id) {
14273 case 0x103c1586:
14274 return 1;
14275 }
14276 return 0;
14277}
14278
14279static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14280{
14281 /* update mute-LED according to the speaker mute state */
14282 if (nid == 0x01 || nid == 0x14) {
14283 int pinval;
14284 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14285 HDA_AMP_MUTE)
14286 pinval = 0x24;
14287 else
14288 pinval = 0x20;
14289 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a542010-03-30 18:03:44 +020014290 snd_hda_codec_update_cache(codec, 0x19, 0,
14291 AC_VERB_SET_PIN_WIDGET_CONTROL,
14292 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014293 }
14294 return alc_check_power_status(codec, nid);
14295}
14296#endif /* CONFIG_SND_HDA_POWER_SAVE */
14297
Takashi Iwai840b64c2010-07-13 22:49:01 +020014298static int alc275_setup_dual_adc(struct hda_codec *codec)
14299{
14300 struct alc_spec *spec = codec->spec;
14301
14302 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14303 return 0;
14304 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14305 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14306 if (spec->ext_mic.pin <= 0x12) {
14307 spec->private_adc_nids[0] = 0x08;
14308 spec->private_adc_nids[1] = 0x11;
14309 spec->private_capsrc_nids[0] = 0x23;
14310 spec->private_capsrc_nids[1] = 0x22;
14311 } else {
14312 spec->private_adc_nids[0] = 0x11;
14313 spec->private_adc_nids[1] = 0x08;
14314 spec->private_capsrc_nids[0] = 0x22;
14315 spec->private_capsrc_nids[1] = 0x23;
14316 }
14317 spec->adc_nids = spec->private_adc_nids;
14318 spec->capsrc_nids = spec->private_capsrc_nids;
14319 spec->num_adc_nids = 2;
14320 spec->dual_adc_switch = 1;
14321 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14322 spec->adc_nids[0], spec->adc_nids[1]);
14323 return 1;
14324 }
14325 return 0;
14326}
14327
Kailang Yangf6a92242007-12-13 16:52:54 +010014328/*
14329 * BIOS auto configuration
14330 */
14331static int alc269_parse_auto_config(struct hda_codec *codec)
14332{
14333 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014334 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014335 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14336
14337 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14338 alc269_ignore);
14339 if (err < 0)
14340 return err;
14341
14342 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14343 if (err < 0)
14344 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014345 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010014346 if (err < 0)
14347 return err;
14348
14349 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14350
Takashi Iwai757899a2010-07-30 10:48:14 +020014351 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014352
Takashi Iwai603c4012008-07-30 15:01:44 +020014353 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014354 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014355
Kailang Yang84898e82010-02-04 14:16:14 +010014356 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
14357 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014358 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014359 } else {
14360 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014361 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014362 }
14363
Kailang Yangf6a92242007-12-13 16:52:54 +010014364 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014365 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014366
14367 if (!alc275_setup_dual_adc(codec))
14368 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14369 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014370
Takashi Iwaie01bf502008-08-21 16:25:07 +020014371 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014372 if (!spec->dual_adc_switch)
Takashi Iwai748cce42010-08-04 07:37:39 +020014373 select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
14374 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014375
14376 err = alc_auto_add_mic_boost(codec);
14377 if (err < 0)
14378 return err;
14379
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014380 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014381 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014382
Kailang Yangf6a92242007-12-13 16:52:54 +010014383 return 1;
14384}
14385
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014386#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14387#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014388#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14389
14390
14391/* init callback for auto-configuration model -- overriding the default init */
14392static void alc269_auto_init(struct hda_codec *codec)
14393{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014394 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014395 alc269_auto_init_multi_out(codec);
14396 alc269_auto_init_hp_out(codec);
14397 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014398 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014399 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014400 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014401}
14402
Takashi Iwaiff818c22010-04-12 08:59:25 +020014403enum {
14404 ALC269_FIXUP_SONY_VAIO,
14405};
14406
Tobias Klauserfbc25662010-05-20 10:40:55 +020014407static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
Takashi Iwaiff818c22010-04-12 08:59:25 +020014408 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14409 {}
14410};
14411
14412static const struct alc_fixup alc269_fixups[] = {
14413 [ALC269_FIXUP_SONY_VAIO] = {
14414 .verbs = alc269_sony_vaio_fixup_verbs
14415 },
14416};
14417
14418static struct snd_pci_quirk alc269_fixup_tbl[] = {
14419 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
14420 {}
14421};
14422
14423
Kailang Yangf6a92242007-12-13 16:52:54 +010014424/*
14425 * configuration and preset
14426 */
14427static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014428 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014429 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014430 [ALC269_AMIC] = "laptop-amic",
14431 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014432 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014433 [ALC269_LIFEBOOK] = "lifebook",
14434 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014435};
14436
14437static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014438 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020014439 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014440 ALC269_AMIC),
14441 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14442 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14443 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14444 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14445 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14446 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14447 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14448 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14449 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14450 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14451 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14452 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14453 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14454 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14455 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14456 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14457 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14458 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14459 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14460 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14461 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14462 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14463 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14464 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14465 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14466 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14467 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14468 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14469 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14470 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14471 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14472 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14473 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14474 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14475 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14476 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014477 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014478 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014479 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014480 ALC269_DMIC),
14481 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14482 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014483 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014484 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014485 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14486 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14487 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14488 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14489 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14490 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014491 {}
14492};
14493
14494static struct alc_config_preset alc269_presets[] = {
14495 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014496 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014497 .init_verbs = { alc269_init_verbs },
14498 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14499 .dac_nids = alc269_dac_nids,
14500 .hp_nid = 0x03,
14501 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14502 .channel_mode = alc269_modes,
14503 .input_mux = &alc269_capture_source,
14504 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014505 [ALC269_QUANTA_FL1] = {
14506 .mixers = { alc269_quanta_fl1_mixer },
14507 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14508 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14509 .dac_nids = alc269_dac_nids,
14510 .hp_nid = 0x03,
14511 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14512 .channel_mode = alc269_modes,
14513 .input_mux = &alc269_capture_source,
14514 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014515 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014516 .init_hook = alc269_quanta_fl1_init_hook,
14517 },
Kailang Yang84898e82010-02-04 14:16:14 +010014518 [ALC269_AMIC] = {
14519 .mixers = { alc269_laptop_mixer },
14520 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014521 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014522 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014523 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14524 .dac_nids = alc269_dac_nids,
14525 .hp_nid = 0x03,
14526 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14527 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014528 .unsol_event = alc269_laptop_unsol_event,
14529 .setup = alc269_laptop_amic_setup,
14530 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014531 },
Kailang Yang84898e82010-02-04 14:16:14 +010014532 [ALC269_DMIC] = {
14533 .mixers = { alc269_laptop_mixer },
14534 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014535 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014536 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014537 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14538 .dac_nids = alc269_dac_nids,
14539 .hp_nid = 0x03,
14540 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14541 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014542 .unsol_event = alc269_laptop_unsol_event,
14543 .setup = alc269_laptop_dmic_setup,
14544 .init_hook = alc269_laptop_inithook,
14545 },
14546 [ALC269VB_AMIC] = {
14547 .mixers = { alc269vb_laptop_mixer },
14548 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14549 .init_verbs = { alc269vb_init_verbs,
14550 alc269vb_laptop_amic_init_verbs },
14551 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14552 .dac_nids = alc269_dac_nids,
14553 .hp_nid = 0x03,
14554 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14555 .channel_mode = alc269_modes,
14556 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014557 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014558 .init_hook = alc269_laptop_inithook,
14559 },
14560 [ALC269VB_DMIC] = {
14561 .mixers = { alc269vb_laptop_mixer },
14562 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14563 .init_verbs = { alc269vb_init_verbs,
14564 alc269vb_laptop_dmic_init_verbs },
14565 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14566 .dac_nids = alc269_dac_nids,
14567 .hp_nid = 0x03,
14568 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14569 .channel_mode = alc269_modes,
14570 .unsol_event = alc269_laptop_unsol_event,
14571 .setup = alc269vb_laptop_dmic_setup,
14572 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014573 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014574 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014575 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014576 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014577 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014578 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014579 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14580 .dac_nids = alc269_dac_nids,
14581 .hp_nid = 0x03,
14582 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14583 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014584 .unsol_event = alc269_laptop_unsol_event,
14585 .setup = alc269_laptop_dmic_setup,
14586 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014587 },
Tony Vroon64154832008-11-06 15:08:49 +000014588 [ALC269_LIFEBOOK] = {
14589 .mixers = { alc269_lifebook_mixer },
14590 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14591 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14592 .dac_nids = alc269_dac_nids,
14593 .hp_nid = 0x03,
14594 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14595 .channel_mode = alc269_modes,
14596 .input_mux = &alc269_capture_source,
14597 .unsol_event = alc269_lifebook_unsol_event,
14598 .init_hook = alc269_lifebook_init_hook,
14599 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014600};
14601
14602static int patch_alc269(struct hda_codec *codec)
14603{
14604 struct alc_spec *spec;
14605 int board_config;
14606 int err;
Kailang Yang84898e82010-02-04 14:16:14 +010014607 int is_alc269vb = 0;
Kailang Yangf6a92242007-12-13 16:52:54 +010014608
14609 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14610 if (spec == NULL)
14611 return -ENOMEM;
14612
14613 codec->spec = spec;
14614
Kailang Yangda00c242010-03-19 11:23:45 +010014615 alc_auto_parse_customize_define(codec);
14616
Kailang Yang274693f2009-12-03 10:07:50 +010014617 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014618 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14619 spec->cdefine.platform_type == 1)
14620 alc_codec_rename(codec, "ALC271X");
14621 else
14622 alc_codec_rename(codec, "ALC259");
Kailang Yang84898e82010-02-04 14:16:14 +010014623 is_alc269vb = 1;
Kailang Yangc027ddc2010-03-19 11:33:06 +010014624 } else
14625 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010014626
Kailang Yangf6a92242007-12-13 16:52:54 +010014627 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14628 alc269_models,
14629 alc269_cfg_tbl);
14630
14631 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014632 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14633 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014634 board_config = ALC269_AUTO;
14635 }
14636
Takashi Iwaiff818c22010-04-12 08:59:25 +020014637 if (board_config == ALC269_AUTO)
14638 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
14639
Kailang Yangf6a92242007-12-13 16:52:54 +010014640 if (board_config == ALC269_AUTO) {
14641 /* automatic parse from the BIOS config */
14642 err = alc269_parse_auto_config(codec);
14643 if (err < 0) {
14644 alc_free(codec);
14645 return err;
14646 } else if (!err) {
14647 printk(KERN_INFO
14648 "hda_codec: Cannot set up configuration "
14649 "from BIOS. Using base mode...\n");
14650 board_config = ALC269_BASIC;
14651 }
14652 }
14653
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014654 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014655 err = snd_hda_attach_beep_device(codec, 0x1);
14656 if (err < 0) {
14657 alc_free(codec);
14658 return err;
14659 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014660 }
14661
Kailang Yangf6a92242007-12-13 16:52:54 +010014662 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014663 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014664
Kailang Yang84898e82010-02-04 14:16:14 +010014665 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014666 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14667 * fix the sample rate of analog I/O to 44.1kHz
14668 */
14669 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14670 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020014671 } else if (spec->dual_adc_switch) {
14672 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14673 /* switch ADC dynamically */
14674 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014675 } else {
14676 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14677 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14678 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014679 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14680 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14681
Takashi Iwai66946352010-03-29 17:21:45 +020014682 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
14683 if (!is_alc269vb) {
14684 spec->adc_nids = alc269_adc_nids;
14685 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14686 spec->capsrc_nids = alc269_capsrc_nids;
14687 } else {
14688 spec->adc_nids = alc269vb_adc_nids;
14689 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14690 spec->capsrc_nids = alc269vb_capsrc_nids;
14691 }
Kailang Yang84898e82010-02-04 14:16:14 +010014692 }
14693
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014694 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014695 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014696 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014697 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014698
Takashi Iwaiff818c22010-04-12 08:59:25 +020014699 if (board_config == ALC269_AUTO)
14700 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
14701
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014702 spec->vmaster_nid = 0x02;
14703
Kailang Yangf6a92242007-12-13 16:52:54 +010014704 codec->patch_ops = alc_patch_ops;
14705 if (board_config == ALC269_AUTO)
14706 spec->init_hook = alc269_auto_init;
14707#ifdef CONFIG_SND_HDA_POWER_SAVE
14708 if (!spec->loopback.amplist)
14709 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014710 if (alc269_mic2_for_mute_led(codec))
14711 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014712#endif
14713
14714 return 0;
14715}
14716
14717/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014718 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14719 */
14720
14721/*
14722 * set the path ways for 2 channel output
14723 * need to set the codec line out and mic 1 pin widgets to inputs
14724 */
14725static struct hda_verb alc861_threestack_ch2_init[] = {
14726 /* set pin widget 1Ah (line in) for input */
14727 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014728 /* set pin widget 18h (mic1/2) for input, for mic also enable
14729 * the vref
14730 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014731 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14732
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014733 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14734#if 0
14735 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14736 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14737#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014738 { } /* end */
14739};
14740/*
14741 * 6ch mode
14742 * need to set the codec line out and mic 1 pin widgets to outputs
14743 */
14744static struct hda_verb alc861_threestack_ch6_init[] = {
14745 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14746 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14747 /* set pin widget 18h (mic1) for output (CLFE)*/
14748 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14749
14750 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014751 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014752
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014753 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14754#if 0
14755 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14756 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14757#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014758 { } /* end */
14759};
14760
14761static struct hda_channel_mode alc861_threestack_modes[2] = {
14762 { 2, alc861_threestack_ch2_init },
14763 { 6, alc861_threestack_ch6_init },
14764};
Takashi Iwai22309c32006-08-09 16:57:28 +020014765/* Set mic1 as input and unmute the mixer */
14766static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
14767 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14768 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14769 { } /* end */
14770};
14771/* Set mic1 as output and mute mixer */
14772static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
14773 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14774 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14775 { } /* end */
14776};
14777
14778static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
14779 { 2, alc861_uniwill_m31_ch2_init },
14780 { 4, alc861_uniwill_m31_ch4_init },
14781};
Kailang Yangdf694da2005-12-05 19:42:22 +010014782
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014783/* Set mic1 and line-in as input and unmute the mixer */
14784static struct hda_verb alc861_asus_ch2_init[] = {
14785 /* set pin widget 1Ah (line in) for input */
14786 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014787 /* set pin widget 18h (mic1/2) for input, for mic also enable
14788 * the vref
14789 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014790 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14791
14792 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14793#if 0
14794 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14795 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14796#endif
14797 { } /* end */
14798};
14799/* Set mic1 nad line-in as output and mute mixer */
14800static struct hda_verb alc861_asus_ch6_init[] = {
14801 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14802 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14803 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14804 /* set pin widget 18h (mic1) for output (CLFE)*/
14805 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14806 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14807 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14808 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14809
14810 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14811#if 0
14812 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14813 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14814#endif
14815 { } /* end */
14816};
14817
14818static struct hda_channel_mode alc861_asus_modes[2] = {
14819 { 2, alc861_asus_ch2_init },
14820 { 6, alc861_asus_ch6_init },
14821};
14822
Kailang Yangdf694da2005-12-05 19:42:22 +010014823/* patch-ALC861 */
14824
14825static struct snd_kcontrol_new alc861_base_mixer[] = {
14826 /* output mixer control */
14827 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14828 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14829 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14830 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14831 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14832
14833 /*Input mixer control */
14834 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14835 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14836 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14837 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14838 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14839 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14840 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14841 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14842 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14843 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014844
Kailang Yangdf694da2005-12-05 19:42:22 +010014845 { } /* end */
14846};
14847
14848static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14849 /* output mixer control */
14850 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14851 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14852 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14853 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14854 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14855
14856 /* Input mixer control */
14857 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14858 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14859 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14860 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14861 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14862 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14863 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14864 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14865 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14866 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014867
Kailang Yangdf694da2005-12-05 19:42:22 +010014868 {
14869 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14870 .name = "Channel Mode",
14871 .info = alc_ch_mode_info,
14872 .get = alc_ch_mode_get,
14873 .put = alc_ch_mode_put,
14874 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14875 },
14876 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014877};
14878
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014879static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014880 /* output mixer control */
14881 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14882 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14883 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014884
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014885 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014886};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014887
Takashi Iwai22309c32006-08-09 16:57:28 +020014888static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14889 /* output mixer control */
14890 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14891 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14892 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14893 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14894 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14895
14896 /* Input mixer control */
14897 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14898 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14899 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14900 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14901 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14902 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14903 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14904 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14905 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14906 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014907
Takashi Iwai22309c32006-08-09 16:57:28 +020014908 {
14909 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14910 .name = "Channel Mode",
14911 .info = alc_ch_mode_info,
14912 .get = alc_ch_mode_get,
14913 .put = alc_ch_mode_put,
14914 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14915 },
14916 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014917};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014918
14919static struct snd_kcontrol_new alc861_asus_mixer[] = {
14920 /* output mixer control */
14921 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14922 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14923 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14924 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14925 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14926
14927 /* Input mixer control */
14928 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14929 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14930 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14931 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14932 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14933 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14934 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14935 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14936 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014937 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14938
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014939 {
14940 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14941 .name = "Channel Mode",
14942 .info = alc_ch_mode_info,
14943 .get = alc_ch_mode_get,
14944 .put = alc_ch_mode_put,
14945 .private_value = ARRAY_SIZE(alc861_asus_modes),
14946 },
14947 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014948};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014949
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014950/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014951static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014952 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14953 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014954 { }
14955};
14956
Kailang Yangdf694da2005-12-05 19:42:22 +010014957/*
14958 * generic initialization of ADC, input mixers and output mixers
14959 */
14960static struct hda_verb alc861_base_init_verbs[] = {
14961 /*
14962 * Unmute ADC0 and set the default input to mic-in
14963 */
14964 /* port-A for surround (rear panel) */
14965 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14966 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14967 /* port-B for mic-in (rear panel) with vref */
14968 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14969 /* port-C for line-in (rear panel) */
14970 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14971 /* port-D for Front */
14972 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14973 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14974 /* port-E for HP out (front panel) */
14975 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14976 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014977 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014978 /* port-F for mic-in (front panel) with vref */
14979 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14980 /* port-G for CLFE (rear panel) */
14981 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14982 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14983 /* port-H for side (rear panel) */
14984 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14985 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14986 /* CD-in */
14987 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14988 /* route front mic to ADC1*/
14989 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14990 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014991
Kailang Yangdf694da2005-12-05 19:42:22 +010014992 /* Unmute DAC0~3 & spdif out*/
14993 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14994 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14995 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14996 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14997 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014998
Kailang Yangdf694da2005-12-05 19:42:22 +010014999 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15000 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15001 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15002 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15003 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015004
Kailang Yangdf694da2005-12-05 19:42:22 +010015005 /* Unmute Stereo Mixer 15 */
15006 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15007 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15008 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015009 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015010
15011 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15012 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15013 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15014 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15015 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15016 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15017 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15018 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015019 /* hp used DAC 3 (Front) */
15020 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015021 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15022
15023 { }
15024};
15025
15026static struct hda_verb alc861_threestack_init_verbs[] = {
15027 /*
15028 * Unmute ADC0 and set the default input to mic-in
15029 */
15030 /* port-A for surround (rear panel) */
15031 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15032 /* port-B for mic-in (rear panel) with vref */
15033 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15034 /* port-C for line-in (rear panel) */
15035 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15036 /* port-D for Front */
15037 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15038 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15039 /* port-E for HP out (front panel) */
15040 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15041 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015042 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015043 /* port-F for mic-in (front panel) with vref */
15044 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15045 /* port-G for CLFE (rear panel) */
15046 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15047 /* port-H for side (rear panel) */
15048 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15049 /* CD-in */
15050 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15051 /* route front mic to ADC1*/
15052 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15053 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15054 /* Unmute DAC0~3 & spdif out*/
15055 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15056 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15057 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15058 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015060
Kailang Yangdf694da2005-12-05 19:42:22 +010015061 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15062 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15063 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15064 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15065 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015066
Kailang Yangdf694da2005-12-05 19:42:22 +010015067 /* Unmute Stereo Mixer 15 */
15068 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15069 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15070 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015071 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015072
15073 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15074 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15075 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15076 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15077 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15078 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15079 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15080 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015081 /* hp used DAC 3 (Front) */
15082 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015083 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15084 { }
15085};
Takashi Iwai22309c32006-08-09 16:57:28 +020015086
15087static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15088 /*
15089 * Unmute ADC0 and set the default input to mic-in
15090 */
15091 /* port-A for surround (rear panel) */
15092 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15093 /* port-B for mic-in (rear panel) with vref */
15094 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15095 /* port-C for line-in (rear panel) */
15096 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15097 /* port-D for Front */
15098 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15099 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15100 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015101 /* this has to be set to VREF80 */
15102 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015103 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015104 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015105 /* port-F for mic-in (front panel) with vref */
15106 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15107 /* port-G for CLFE (rear panel) */
15108 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15109 /* port-H for side (rear panel) */
15110 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15111 /* CD-in */
15112 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15113 /* route front mic to ADC1*/
15114 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15115 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15116 /* Unmute DAC0~3 & spdif out*/
15117 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15118 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15119 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15120 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15121 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015122
Takashi Iwai22309c32006-08-09 16:57:28 +020015123 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15124 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15125 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15126 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15127 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015128
Takashi Iwai22309c32006-08-09 16:57:28 +020015129 /* Unmute Stereo Mixer 15 */
15130 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15131 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15132 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015133 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015134
15135 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15136 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15137 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15138 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15139 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15140 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15141 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15142 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015143 /* hp used DAC 3 (Front) */
15144 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015145 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15146 { }
15147};
15148
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015149static struct hda_verb alc861_asus_init_verbs[] = {
15150 /*
15151 * Unmute ADC0 and set the default input to mic-in
15152 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015153 /* port-A for surround (rear panel)
15154 * according to codec#0 this is the HP jack
15155 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015156 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15157 /* route front PCM to HP */
15158 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15159 /* port-B for mic-in (rear panel) with vref */
15160 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15161 /* port-C for line-in (rear panel) */
15162 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15163 /* port-D for Front */
15164 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15165 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15166 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015167 /* this has to be set to VREF80 */
15168 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015169 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015170 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015171 /* port-F for mic-in (front panel) with vref */
15172 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15173 /* port-G for CLFE (rear panel) */
15174 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15175 /* port-H for side (rear panel) */
15176 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15177 /* CD-in */
15178 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15179 /* route front mic to ADC1*/
15180 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15181 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15182 /* Unmute DAC0~3 & spdif out*/
15183 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15184 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15185 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15186 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15187 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15188 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15189 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15190 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15191 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15192 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015193
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015194 /* Unmute Stereo Mixer 15 */
15195 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15196 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15197 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015198 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015199
15200 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15201 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15202 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15203 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15204 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15205 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15206 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15207 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015208 /* hp used DAC 3 (Front) */
15209 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015210 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15211 { }
15212};
15213
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015214/* additional init verbs for ASUS laptops */
15215static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15216 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15217 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15218 { }
15219};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015220
Kailang Yangdf694da2005-12-05 19:42:22 +010015221/*
15222 * generic initialization of ADC, input mixers and output mixers
15223 */
15224static struct hda_verb alc861_auto_init_verbs[] = {
15225 /*
15226 * Unmute ADC0 and set the default input to mic-in
15227 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015228 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015229 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015230
Kailang Yangdf694da2005-12-05 19:42:22 +010015231 /* Unmute DAC0~3 & spdif out*/
15232 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15233 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15234 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15235 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15236 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015237
Kailang Yangdf694da2005-12-05 19:42:22 +010015238 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15239 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15240 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15241 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15242 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015243
Kailang Yangdf694da2005-12-05 19:42:22 +010015244 /* Unmute Stereo Mixer 15 */
15245 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15246 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15247 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15248 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15249
Takashi Iwai1c209302009-07-22 15:17:45 +020015250 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15251 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15252 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15253 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15254 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15255 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15256 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15257 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015258
15259 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15260 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015261 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15262 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015263 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15264 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015265 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15266 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015267
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015268 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015269
15270 { }
15271};
15272
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015273static struct hda_verb alc861_toshiba_init_verbs[] = {
15274 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015275
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015276 { }
15277};
15278
15279/* toggle speaker-output according to the hp-jack state */
15280static void alc861_toshiba_automute(struct hda_codec *codec)
15281{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015282 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015283
Takashi Iwai47fd8302007-08-10 17:11:07 +020015284 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15285 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15286 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15287 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015288}
15289
15290static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15291 unsigned int res)
15292{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015293 if ((res >> 26) == ALC880_HP_EVENT)
15294 alc861_toshiba_automute(codec);
15295}
15296
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015297/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015298#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15299#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15300#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15301#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15302
15303
15304#define ALC861_DIGOUT_NID 0x07
15305
15306static struct hda_channel_mode alc861_8ch_modes[1] = {
15307 { 8, NULL }
15308};
15309
15310static hda_nid_t alc861_dac_nids[4] = {
15311 /* front, surround, clfe, side */
15312 0x03, 0x06, 0x05, 0x04
15313};
15314
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015315static hda_nid_t alc660_dac_nids[3] = {
15316 /* front, clfe, surround */
15317 0x03, 0x05, 0x06
15318};
15319
Kailang Yangdf694da2005-12-05 19:42:22 +010015320static hda_nid_t alc861_adc_nids[1] = {
15321 /* ADC0-2 */
15322 0x08,
15323};
15324
15325static struct hda_input_mux alc861_capture_source = {
15326 .num_items = 5,
15327 .items = {
15328 { "Mic", 0x0 },
15329 { "Front Mic", 0x3 },
15330 { "Line", 0x1 },
15331 { "CD", 0x4 },
15332 { "Mixer", 0x5 },
15333 },
15334};
15335
Takashi Iwai1c209302009-07-22 15:17:45 +020015336static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15337{
15338 struct alc_spec *spec = codec->spec;
15339 hda_nid_t mix, srcs[5];
15340 int i, j, num;
15341
15342 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15343 return 0;
15344 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15345 if (num < 0)
15346 return 0;
15347 for (i = 0; i < num; i++) {
15348 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015349 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015350 if (type != AC_WID_AUD_OUT)
15351 continue;
15352 for (j = 0; j < spec->multiout.num_dacs; j++)
15353 if (spec->multiout.dac_nids[j] == srcs[i])
15354 break;
15355 if (j >= spec->multiout.num_dacs)
15356 return srcs[i];
15357 }
15358 return 0;
15359}
15360
Kailang Yangdf694da2005-12-05 19:42:22 +010015361/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015362static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015363 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015364{
Takashi Iwai1c209302009-07-22 15:17:45 +020015365 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015366 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015367 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015368
15369 spec->multiout.dac_nids = spec->private_dac_nids;
15370 for (i = 0; i < cfg->line_outs; i++) {
15371 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015372 dac = alc861_look_for_dac(codec, nid);
15373 if (!dac)
15374 continue;
15375 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015376 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015377 return 0;
15378}
15379
Takashi Iwai1c209302009-07-22 15:17:45 +020015380static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15381 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015382{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015383 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015384 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15385}
15386
15387/* add playback controls from the parsed DAC table */
15388static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15389 const struct auto_pin_cfg *cfg)
15390{
15391 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015392 static const char *chname[4] = {
15393 "Front", "Surround", NULL /*CLFE*/, "Side"
15394 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015395 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015396 int i, err;
15397
15398 if (cfg->line_outs == 1) {
15399 const char *pfx = NULL;
15400 if (!cfg->hp_outs)
15401 pfx = "Master";
15402 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15403 pfx = "Speaker";
15404 if (pfx) {
15405 nid = spec->multiout.dac_nids[0];
15406 return alc861_create_out_sw(codec, pfx, nid, 3);
15407 }
15408 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015409
15410 for (i = 0; i < cfg->line_outs; i++) {
15411 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015412 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015413 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015414 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015415 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015416 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015417 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015418 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015419 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015420 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015421 return err;
15422 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015423 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015424 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015425 return err;
15426 }
15427 }
15428 return 0;
15429}
15430
Takashi Iwai1c209302009-07-22 15:17:45 +020015431static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015432{
Takashi Iwai1c209302009-07-22 15:17:45 +020015433 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015434 int err;
15435 hda_nid_t nid;
15436
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015437 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015438 return 0;
15439
15440 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015441 nid = alc861_look_for_dac(codec, pin);
15442 if (nid) {
15443 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15444 if (err < 0)
15445 return err;
15446 spec->multiout.hp_nid = nid;
15447 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015448 }
15449 return 0;
15450}
15451
15452/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015453static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015454 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015455{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015456 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015457}
15458
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015459static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15460 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015461 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015462{
Takashi Iwai1c209302009-07-22 15:17:45 +020015463 hda_nid_t mix, srcs[5];
15464 int i, num;
15465
Jacek Luczak564c5be2008-05-03 18:41:23 +020015466 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15467 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015468 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015469 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015470 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15471 return;
15472 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15473 if (num < 0)
15474 return;
15475 for (i = 0; i < num; i++) {
15476 unsigned int mute;
15477 if (srcs[i] == dac || srcs[i] == 0x15)
15478 mute = AMP_IN_UNMUTE(i);
15479 else
15480 mute = AMP_IN_MUTE(i);
15481 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15482 mute);
15483 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015484}
15485
15486static void alc861_auto_init_multi_out(struct hda_codec *codec)
15487{
15488 struct alc_spec *spec = codec->spec;
15489 int i;
15490
15491 for (i = 0; i < spec->autocfg.line_outs; i++) {
15492 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015493 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015494 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015495 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015496 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015497 }
15498}
15499
15500static void alc861_auto_init_hp_out(struct hda_codec *codec)
15501{
15502 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015503
Takashi Iwai15870f02009-10-05 08:25:13 +020015504 if (spec->autocfg.hp_outs)
15505 alc861_auto_set_output_and_unmute(codec,
15506 spec->autocfg.hp_pins[0],
15507 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015508 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015509 if (spec->autocfg.speaker_outs)
15510 alc861_auto_set_output_and_unmute(codec,
15511 spec->autocfg.speaker_pins[0],
15512 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015513 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015514}
15515
15516static void alc861_auto_init_analog_input(struct hda_codec *codec)
15517{
15518 struct alc_spec *spec = codec->spec;
15519 int i;
15520
15521 for (i = 0; i < AUTO_PIN_LAST; i++) {
15522 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010015523 if (nid >= 0x0c && nid <= 0x11)
15524 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010015525 }
15526}
15527
15528/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015529/* return 1 if successful, 0 if the proper config is not found,
15530 * or a negative error code
15531 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015532static int alc861_parse_auto_config(struct hda_codec *codec)
15533{
15534 struct alc_spec *spec = codec->spec;
15535 int err;
15536 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15537
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015538 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15539 alc861_ignore);
15540 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015541 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015542 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015543 return 0; /* can't find valid BIOS pin config */
15544
Takashi Iwai1c209302009-07-22 15:17:45 +020015545 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015546 if (err < 0)
15547 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015548 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015549 if (err < 0)
15550 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015551 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015552 if (err < 0)
15553 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015554 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015555 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015556 return err;
15557
15558 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15559
Takashi Iwai757899a2010-07-30 10:48:14 +020015560 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015561
Takashi Iwai603c4012008-07-30 15:01:44 +020015562 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015563 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015564
Takashi Iwaid88897e2008-10-31 15:01:37 +010015565 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015566
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015567 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015568 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015569
15570 spec->adc_nids = alc861_adc_nids;
15571 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015572 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015573
Kailang Yang6227cdc2010-02-25 08:36:52 +010015574 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015575
Kailang Yangdf694da2005-12-05 19:42:22 +010015576 return 1;
15577}
15578
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015579/* additional initialization for auto-configuration model */
15580static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015581{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015582 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015583 alc861_auto_init_multi_out(codec);
15584 alc861_auto_init_hp_out(codec);
15585 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015586 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015587 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015588 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015589}
15590
Takashi Iwaicb53c622007-08-10 17:21:45 +020015591#ifdef CONFIG_SND_HDA_POWER_SAVE
15592static struct hda_amp_list alc861_loopbacks[] = {
15593 { 0x15, HDA_INPUT, 0 },
15594 { 0x15, HDA_INPUT, 1 },
15595 { 0x15, HDA_INPUT, 2 },
15596 { 0x15, HDA_INPUT, 3 },
15597 { } /* end */
15598};
15599#endif
15600
Kailang Yangdf694da2005-12-05 19:42:22 +010015601
15602/*
15603 * configuration and preset
15604 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015605static const char *alc861_models[ALC861_MODEL_LAST] = {
15606 [ALC861_3ST] = "3stack",
15607 [ALC660_3ST] = "3stack-660",
15608 [ALC861_3ST_DIG] = "3stack-dig",
15609 [ALC861_6ST_DIG] = "6stack-dig",
15610 [ALC861_UNIWILL_M31] = "uniwill-m31",
15611 [ALC861_TOSHIBA] = "toshiba",
15612 [ALC861_ASUS] = "asus",
15613 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15614 [ALC861_AUTO] = "auto",
15615};
15616
15617static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015618 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015619 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15620 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15621 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015622 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015623 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015624 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015625 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15626 * Any other models that need this preset?
15627 */
15628 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015629 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15630 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015631 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15632 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15633 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15634 /* FIXME: the below seems conflict */
15635 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15636 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15637 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015638 {}
15639};
15640
15641static struct alc_config_preset alc861_presets[] = {
15642 [ALC861_3ST] = {
15643 .mixers = { alc861_3ST_mixer },
15644 .init_verbs = { alc861_threestack_init_verbs },
15645 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15646 .dac_nids = alc861_dac_nids,
15647 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15648 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015649 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015650 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15651 .adc_nids = alc861_adc_nids,
15652 .input_mux = &alc861_capture_source,
15653 },
15654 [ALC861_3ST_DIG] = {
15655 .mixers = { alc861_base_mixer },
15656 .init_verbs = { alc861_threestack_init_verbs },
15657 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15658 .dac_nids = alc861_dac_nids,
15659 .dig_out_nid = ALC861_DIGOUT_NID,
15660 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15661 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015662 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015663 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15664 .adc_nids = alc861_adc_nids,
15665 .input_mux = &alc861_capture_source,
15666 },
15667 [ALC861_6ST_DIG] = {
15668 .mixers = { alc861_base_mixer },
15669 .init_verbs = { alc861_base_init_verbs },
15670 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15671 .dac_nids = alc861_dac_nids,
15672 .dig_out_nid = ALC861_DIGOUT_NID,
15673 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15674 .channel_mode = alc861_8ch_modes,
15675 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15676 .adc_nids = alc861_adc_nids,
15677 .input_mux = &alc861_capture_source,
15678 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015679 [ALC660_3ST] = {
15680 .mixers = { alc861_3ST_mixer },
15681 .init_verbs = { alc861_threestack_init_verbs },
15682 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15683 .dac_nids = alc660_dac_nids,
15684 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15685 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015686 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015687 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15688 .adc_nids = alc861_adc_nids,
15689 .input_mux = &alc861_capture_source,
15690 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015691 [ALC861_UNIWILL_M31] = {
15692 .mixers = { alc861_uniwill_m31_mixer },
15693 .init_verbs = { alc861_uniwill_m31_init_verbs },
15694 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15695 .dac_nids = alc861_dac_nids,
15696 .dig_out_nid = ALC861_DIGOUT_NID,
15697 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15698 .channel_mode = alc861_uniwill_m31_modes,
15699 .need_dac_fix = 1,
15700 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15701 .adc_nids = alc861_adc_nids,
15702 .input_mux = &alc861_capture_source,
15703 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015704 [ALC861_TOSHIBA] = {
15705 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015706 .init_verbs = { alc861_base_init_verbs,
15707 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015708 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15709 .dac_nids = alc861_dac_nids,
15710 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15711 .channel_mode = alc883_3ST_2ch_modes,
15712 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15713 .adc_nids = alc861_adc_nids,
15714 .input_mux = &alc861_capture_source,
15715 .unsol_event = alc861_toshiba_unsol_event,
15716 .init_hook = alc861_toshiba_automute,
15717 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015718 [ALC861_ASUS] = {
15719 .mixers = { alc861_asus_mixer },
15720 .init_verbs = { alc861_asus_init_verbs },
15721 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15722 .dac_nids = alc861_dac_nids,
15723 .dig_out_nid = ALC861_DIGOUT_NID,
15724 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15725 .channel_mode = alc861_asus_modes,
15726 .need_dac_fix = 1,
15727 .hp_nid = 0x06,
15728 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15729 .adc_nids = alc861_adc_nids,
15730 .input_mux = &alc861_capture_source,
15731 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015732 [ALC861_ASUS_LAPTOP] = {
15733 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15734 .init_verbs = { alc861_asus_init_verbs,
15735 alc861_asus_laptop_init_verbs },
15736 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15737 .dac_nids = alc861_dac_nids,
15738 .dig_out_nid = ALC861_DIGOUT_NID,
15739 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15740 .channel_mode = alc883_3ST_2ch_modes,
15741 .need_dac_fix = 1,
15742 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15743 .adc_nids = alc861_adc_nids,
15744 .input_mux = &alc861_capture_source,
15745 },
15746};
Kailang Yangdf694da2005-12-05 19:42:22 +010015747
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015748/* Pin config fixes */
15749enum {
15750 PINFIX_FSC_AMILO_PI1505,
15751};
15752
15753static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
15754 { 0x0b, 0x0221101f }, /* HP */
15755 { 0x0f, 0x90170310 }, /* speaker */
15756 { }
15757};
15758
15759static const struct alc_fixup alc861_fixups[] = {
15760 [PINFIX_FSC_AMILO_PI1505] = {
15761 .pins = alc861_fsc_amilo_pi1505_pinfix
15762 },
15763};
15764
15765static struct snd_pci_quirk alc861_fixup_tbl[] = {
15766 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15767 {}
15768};
Kailang Yangdf694da2005-12-05 19:42:22 +010015769
15770static int patch_alc861(struct hda_codec *codec)
15771{
15772 struct alc_spec *spec;
15773 int board_config;
15774 int err;
15775
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015776 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015777 if (spec == NULL)
15778 return -ENOMEM;
15779
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015780 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015781
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015782 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15783 alc861_models,
15784 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015785
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015786 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015787 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15788 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015789 board_config = ALC861_AUTO;
15790 }
15791
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015792 if (board_config == ALC861_AUTO)
15793 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015794
Kailang Yangdf694da2005-12-05 19:42:22 +010015795 if (board_config == ALC861_AUTO) {
15796 /* automatic parse from the BIOS config */
15797 err = alc861_parse_auto_config(codec);
15798 if (err < 0) {
15799 alc_free(codec);
15800 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015801 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015802 printk(KERN_INFO
15803 "hda_codec: Cannot set up configuration "
15804 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015805 board_config = ALC861_3ST_DIG;
15806 }
15807 }
15808
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015809 err = snd_hda_attach_beep_device(codec, 0x23);
15810 if (err < 0) {
15811 alc_free(codec);
15812 return err;
15813 }
15814
Kailang Yangdf694da2005-12-05 19:42:22 +010015815 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015816 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015817
Kailang Yangdf694da2005-12-05 19:42:22 +010015818 spec->stream_analog_playback = &alc861_pcm_analog_playback;
15819 spec->stream_analog_capture = &alc861_pcm_analog_capture;
15820
Kailang Yangdf694da2005-12-05 19:42:22 +010015821 spec->stream_digital_playback = &alc861_pcm_digital_playback;
15822 spec->stream_digital_capture = &alc861_pcm_digital_capture;
15823
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015824 if (!spec->cap_mixer)
15825 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015826 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15827
Takashi Iwai2134ea42008-01-10 16:53:55 +010015828 spec->vmaster_nid = 0x03;
15829
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015830 if (board_config == ALC861_AUTO)
15831 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
15832
Kailang Yangdf694da2005-12-05 19:42:22 +010015833 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015834 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015835 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015836#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015837 spec->power_hook = alc_power_eapd;
15838#endif
15839 }
15840#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015841 if (!spec->loopback.amplist)
15842 spec->loopback.amplist = alc861_loopbacks;
15843#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015844
Kailang Yangdf694da2005-12-05 19:42:22 +010015845 return 0;
15846}
15847
15848/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015849 * ALC861-VD support
15850 *
15851 * Based on ALC882
15852 *
15853 * In addition, an independent DAC
15854 */
15855#define ALC861VD_DIGOUT_NID 0x06
15856
15857static hda_nid_t alc861vd_dac_nids[4] = {
15858 /* front, surr, clfe, side surr */
15859 0x02, 0x03, 0x04, 0x05
15860};
15861
15862/* dac_nids for ALC660vd are in a different order - according to
15863 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015864 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015865 * of ALC660vd codecs, but for now there is only 3stack mixer
15866 * - and it is the same as in 861vd.
15867 * adc_nids in ALC660vd are (is) the same as in 861vd
15868 */
15869static hda_nid_t alc660vd_dac_nids[3] = {
15870 /* front, rear, clfe, rear_surr */
15871 0x02, 0x04, 0x03
15872};
15873
15874static hda_nid_t alc861vd_adc_nids[1] = {
15875 /* ADC0 */
15876 0x09,
15877};
15878
Takashi Iwaie1406342008-02-11 18:32:32 +010015879static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15880
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015881/* input MUX */
15882/* FIXME: should be a matrix-type input source selection */
15883static struct hda_input_mux alc861vd_capture_source = {
15884 .num_items = 4,
15885 .items = {
15886 { "Mic", 0x0 },
15887 { "Front Mic", 0x1 },
15888 { "Line", 0x2 },
15889 { "CD", 0x4 },
15890 },
15891};
15892
Kailang Yang272a5272007-05-14 11:00:38 +020015893static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015894 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015895 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015896 { "Ext Mic", 0x0 },
15897 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015898 },
15899};
15900
Kailang Yangd1a991a2007-08-15 16:21:59 +020015901static struct hda_input_mux alc861vd_hp_capture_source = {
15902 .num_items = 2,
15903 .items = {
15904 { "Front Mic", 0x0 },
15905 { "ATAPI Mic", 0x1 },
15906 },
15907};
15908
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015909/*
15910 * 2ch mode
15911 */
15912static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15913 { 2, NULL }
15914};
15915
15916/*
15917 * 6ch mode
15918 */
15919static struct hda_verb alc861vd_6stack_ch6_init[] = {
15920 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15921 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15922 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15923 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15924 { } /* end */
15925};
15926
15927/*
15928 * 8ch mode
15929 */
15930static struct hda_verb alc861vd_6stack_ch8_init[] = {
15931 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15932 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15933 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15934 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15935 { } /* end */
15936};
15937
15938static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15939 { 6, alc861vd_6stack_ch6_init },
15940 { 8, alc861vd_6stack_ch8_init },
15941};
15942
15943static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15944 {
15945 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15946 .name = "Channel Mode",
15947 .info = alc_ch_mode_info,
15948 .get = alc_ch_mode_get,
15949 .put = alc_ch_mode_put,
15950 },
15951 { } /* end */
15952};
15953
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015954/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15955 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15956 */
15957static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15958 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15959 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15960
15961 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15962 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15963
15964 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15965 HDA_OUTPUT),
15966 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15967 HDA_OUTPUT),
15968 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15969 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15970
15971 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15972 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15973
15974 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15975
15976 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15977 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15978 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15979
15980 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15981 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15982 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15983
15984 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15985 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15986
15987 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15988 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15989
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015990 { } /* end */
15991};
15992
15993static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15994 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15995 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15996
15997 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15998
15999 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16000 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16001 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16002
16003 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16004 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16005 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16006
16007 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16008 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16009
16010 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16011 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16012
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016013 { } /* end */
16014};
16015
Kailang Yangbdd148a2007-05-08 15:19:08 +020016016static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16017 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16018 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16019 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16020
16021 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16022
16023 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16024 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16025 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16026
16027 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16028 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16029 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16030
16031 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16032 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16033
16034 { } /* end */
16035};
16036
Tobin Davisb419f342008-03-07 11:57:51 +010016037/* Pin assignment: Speaker=0x14, HP = 0x15,
16038 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016039 */
16040static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016041 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16042 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016043 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16044 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010016045 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16046 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16047 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16048 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16049 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16050 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016051 { } /* end */
16052};
16053
Kailang Yangd1a991a2007-08-15 16:21:59 +020016054/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16055 * Front Mic=0x18, ATAPI Mic = 0x19,
16056 */
16057static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16058 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16059 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16060 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16061 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16062 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16063 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16064 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16065 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016066
Kailang Yangd1a991a2007-08-15 16:21:59 +020016067 { } /* end */
16068};
16069
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016070/*
16071 * generic initialization of ADC, input mixers and output mixers
16072 */
16073static struct hda_verb alc861vd_volume_init_verbs[] = {
16074 /*
16075 * Unmute ADC0 and set the default input to mic-in
16076 */
16077 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16078 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16079
16080 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16081 * the analog-loopback mixer widget
16082 */
16083 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016084 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16085 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16086 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16087 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16088 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016089
16090 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016091 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16092 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16093 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016094 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016095
16096 /*
16097 * Set up output mixers (0x02 - 0x05)
16098 */
16099 /* set vol=0 to output mixers */
16100 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16101 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16102 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16103 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16104
16105 /* set up input amps for analog loopback */
16106 /* Amp Indices: DAC = 0, mixer = 1 */
16107 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16108 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16109 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16110 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16111 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16112 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16113 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16114 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16115
16116 { }
16117};
16118
16119/*
16120 * 3-stack pin configuration:
16121 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16122 */
16123static struct hda_verb alc861vd_3stack_init_verbs[] = {
16124 /*
16125 * Set pin mode and muting
16126 */
16127 /* set front pin widgets 0x14 for output */
16128 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16129 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16130 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16131
16132 /* Mic (rear) pin: input vref at 80% */
16133 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16134 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16135 /* Front Mic pin: input vref at 80% */
16136 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16137 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16138 /* Line In pin: input */
16139 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16140 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16141 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16142 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16143 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16144 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16145 /* CD pin widget for input */
16146 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16147
16148 { }
16149};
16150
16151/*
16152 * 6-stack pin configuration:
16153 */
16154static struct hda_verb alc861vd_6stack_init_verbs[] = {
16155 /*
16156 * Set pin mode and muting
16157 */
16158 /* set front pin widgets 0x14 for output */
16159 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16160 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16161 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16162
16163 /* Rear Pin: output 1 (0x0d) */
16164 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16165 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16166 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16167 /* CLFE Pin: output 2 (0x0e) */
16168 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16169 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16170 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16171 /* Side Pin: output 3 (0x0f) */
16172 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16173 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16174 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16175
16176 /* Mic (rear) pin: input vref at 80% */
16177 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16178 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16179 /* Front Mic pin: input vref at 80% */
16180 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16181 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16182 /* Line In pin: input */
16183 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16184 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16185 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16186 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16187 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16188 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16189 /* CD pin widget for input */
16190 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16191
16192 { }
16193};
16194
Kailang Yangbdd148a2007-05-08 15:19:08 +020016195static struct hda_verb alc861vd_eapd_verbs[] = {
16196 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16197 { }
16198};
16199
Kailang Yangf9423e72008-05-27 12:32:25 +020016200static struct hda_verb alc660vd_eapd_verbs[] = {
16201 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16202 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16203 { }
16204};
16205
Kailang Yangbdd148a2007-05-08 15:19:08 +020016206static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16207 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16208 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16209 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16210 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016211 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016212 {}
16213};
16214
Kailang Yangbdd148a2007-05-08 15:19:08 +020016215static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16216{
16217 unsigned int present;
16218 unsigned char bits;
16219
Wu Fengguang864f92b2009-11-18 12:38:02 +080016220 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016221 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016222
Takashi Iwai47fd8302007-08-10 17:11:07 +020016223 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16224 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016225}
16226
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016227static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016228{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016229 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016230 spec->autocfg.hp_pins[0] = 0x1b;
16231 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016232}
16233
16234static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16235{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016236 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016237 alc861vd_lenovo_mic_automute(codec);
16238}
16239
16240static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16241 unsigned int res)
16242{
16243 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016244 case ALC880_MIC_EVENT:
16245 alc861vd_lenovo_mic_automute(codec);
16246 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016247 default:
16248 alc_automute_amp_unsol_event(codec, res);
16249 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016250 }
16251}
16252
Kailang Yang272a5272007-05-14 11:00:38 +020016253static struct hda_verb alc861vd_dallas_verbs[] = {
16254 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16255 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16256 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16257 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16258
16259 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16260 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16261 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16262 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16263 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16264 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16265 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16266 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016267
Kailang Yang272a5272007-05-14 11:00:38 +020016268 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16269 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16270 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16271 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16272 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16273 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16274 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16275 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16276
16277 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16278 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16279 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16280 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16281 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16282 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16283 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16284 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16285
16286 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16287 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16288 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16289 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16290
16291 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016292 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016293 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16294
16295 { } /* end */
16296};
16297
16298/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016299static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016300{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016301 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016302
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016303 spec->autocfg.hp_pins[0] = 0x15;
16304 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016305}
16306
Takashi Iwaicb53c622007-08-10 17:21:45 +020016307#ifdef CONFIG_SND_HDA_POWER_SAVE
16308#define alc861vd_loopbacks alc880_loopbacks
16309#endif
16310
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016311/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016312#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16313#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16314#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16315#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16316
16317/*
16318 * configuration and preset
16319 */
16320static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16321 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016322 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016323 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016324 [ALC861VD_3ST] = "3stack",
16325 [ALC861VD_3ST_DIG] = "3stack-digout",
16326 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016327 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016328 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016329 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016330 [ALC861VD_AUTO] = "auto",
16331};
16332
16333static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016334 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16335 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016336 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016337 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016338 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016339 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016340 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016341 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016342 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016343 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016344 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016345 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016346 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016347 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016348 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016349 {}
16350};
16351
16352static struct alc_config_preset alc861vd_presets[] = {
16353 [ALC660VD_3ST] = {
16354 .mixers = { alc861vd_3st_mixer },
16355 .init_verbs = { alc861vd_volume_init_verbs,
16356 alc861vd_3stack_init_verbs },
16357 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16358 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016359 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16360 .channel_mode = alc861vd_3stack_2ch_modes,
16361 .input_mux = &alc861vd_capture_source,
16362 },
Mike Crash6963f842007-06-25 12:12:51 +020016363 [ALC660VD_3ST_DIG] = {
16364 .mixers = { alc861vd_3st_mixer },
16365 .init_verbs = { alc861vd_volume_init_verbs,
16366 alc861vd_3stack_init_verbs },
16367 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16368 .dac_nids = alc660vd_dac_nids,
16369 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016370 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16371 .channel_mode = alc861vd_3stack_2ch_modes,
16372 .input_mux = &alc861vd_capture_source,
16373 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016374 [ALC861VD_3ST] = {
16375 .mixers = { alc861vd_3st_mixer },
16376 .init_verbs = { alc861vd_volume_init_verbs,
16377 alc861vd_3stack_init_verbs },
16378 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16379 .dac_nids = alc861vd_dac_nids,
16380 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16381 .channel_mode = alc861vd_3stack_2ch_modes,
16382 .input_mux = &alc861vd_capture_source,
16383 },
16384 [ALC861VD_3ST_DIG] = {
16385 .mixers = { alc861vd_3st_mixer },
16386 .init_verbs = { alc861vd_volume_init_verbs,
16387 alc861vd_3stack_init_verbs },
16388 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16389 .dac_nids = alc861vd_dac_nids,
16390 .dig_out_nid = ALC861VD_DIGOUT_NID,
16391 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16392 .channel_mode = alc861vd_3stack_2ch_modes,
16393 .input_mux = &alc861vd_capture_source,
16394 },
16395 [ALC861VD_6ST_DIG] = {
16396 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16397 .init_verbs = { alc861vd_volume_init_verbs,
16398 alc861vd_6stack_init_verbs },
16399 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16400 .dac_nids = alc861vd_dac_nids,
16401 .dig_out_nid = ALC861VD_DIGOUT_NID,
16402 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16403 .channel_mode = alc861vd_6stack_modes,
16404 .input_mux = &alc861vd_capture_source,
16405 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016406 [ALC861VD_LENOVO] = {
16407 .mixers = { alc861vd_lenovo_mixer },
16408 .init_verbs = { alc861vd_volume_init_verbs,
16409 alc861vd_3stack_init_verbs,
16410 alc861vd_eapd_verbs,
16411 alc861vd_lenovo_unsol_verbs },
16412 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16413 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016414 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16415 .channel_mode = alc861vd_3stack_2ch_modes,
16416 .input_mux = &alc861vd_capture_source,
16417 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016418 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016419 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016420 },
Kailang Yang272a5272007-05-14 11:00:38 +020016421 [ALC861VD_DALLAS] = {
16422 .mixers = { alc861vd_dallas_mixer },
16423 .init_verbs = { alc861vd_dallas_verbs },
16424 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16425 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016426 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16427 .channel_mode = alc861vd_3stack_2ch_modes,
16428 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016429 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016430 .setup = alc861vd_dallas_setup,
16431 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016432 },
16433 [ALC861VD_HP] = {
16434 .mixers = { alc861vd_hp_mixer },
16435 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16436 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16437 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016438 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016439 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16440 .channel_mode = alc861vd_3stack_2ch_modes,
16441 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016442 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016443 .setup = alc861vd_dallas_setup,
16444 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016445 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016446 [ALC660VD_ASUS_V1S] = {
16447 .mixers = { alc861vd_lenovo_mixer },
16448 .init_verbs = { alc861vd_volume_init_verbs,
16449 alc861vd_3stack_init_verbs,
16450 alc861vd_eapd_verbs,
16451 alc861vd_lenovo_unsol_verbs },
16452 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16453 .dac_nids = alc660vd_dac_nids,
16454 .dig_out_nid = ALC861VD_DIGOUT_NID,
16455 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16456 .channel_mode = alc861vd_3stack_2ch_modes,
16457 .input_mux = &alc861vd_capture_source,
16458 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016459 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016460 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016461 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016462};
16463
16464/*
16465 * BIOS auto configuration
16466 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016467static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16468 const struct auto_pin_cfg *cfg)
16469{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016470 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016471}
16472
16473
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016474static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16475 hda_nid_t nid, int pin_type, int dac_idx)
16476{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016477 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016478}
16479
16480static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16481{
16482 struct alc_spec *spec = codec->spec;
16483 int i;
16484
16485 for (i = 0; i <= HDA_SIDE; i++) {
16486 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016487 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016488 if (nid)
16489 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016490 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016491 }
16492}
16493
16494
16495static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16496{
16497 struct alc_spec *spec = codec->spec;
16498 hda_nid_t pin;
16499
16500 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016501 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016502 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016503 pin = spec->autocfg.speaker_pins[0];
16504 if (pin)
16505 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016506}
16507
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016508#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16509
16510static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16511{
16512 struct alc_spec *spec = codec->spec;
16513 int i;
16514
16515 for (i = 0; i < AUTO_PIN_LAST; i++) {
16516 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020016517 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016518 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016519 if (nid != ALC861VD_PIN_CD_NID &&
16520 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016521 snd_hda_codec_write(codec, nid, 0,
16522 AC_VERB_SET_AMP_GAIN_MUTE,
16523 AMP_OUT_MUTE);
16524 }
16525 }
16526}
16527
Takashi Iwaif511b012008-08-15 16:46:42 +020016528#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16529
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016530#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16531#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16532
16533/* add playback controls from the parsed DAC table */
16534/* Based on ALC880 version. But ALC861VD has separate,
16535 * different NIDs for mute/unmute switch and volume control */
16536static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16537 const struct auto_pin_cfg *cfg)
16538{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016539 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16540 hda_nid_t nid_v, nid_s;
16541 int i, err;
16542
16543 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016544 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016545 continue;
16546 nid_v = alc861vd_idx_to_mixer_vol(
16547 alc880_dac_to_idx(
16548 spec->multiout.dac_nids[i]));
16549 nid_s = alc861vd_idx_to_mixer_switch(
16550 alc880_dac_to_idx(
16551 spec->multiout.dac_nids[i]));
16552
16553 if (i == 2) {
16554 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016555 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16556 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016557 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16558 HDA_OUTPUT));
16559 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016560 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016561 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16562 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016563 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16564 HDA_OUTPUT));
16565 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016566 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016567 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16568 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016569 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16570 HDA_INPUT));
16571 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016572 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016573 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16574 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016575 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16576 HDA_INPUT));
16577 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016578 return err;
16579 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016580 const char *pfx;
16581 if (cfg->line_outs == 1 &&
16582 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16583 if (!cfg->hp_pins)
16584 pfx = "Speaker";
16585 else
16586 pfx = "PCM";
16587 } else
16588 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016589 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016590 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16591 HDA_OUTPUT));
16592 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016593 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016594 if (cfg->line_outs == 1 &&
16595 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16596 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016597 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016598 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016599 HDA_INPUT));
16600 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016601 return err;
16602 }
16603 }
16604 return 0;
16605}
16606
16607/* add playback controls for speaker and HP outputs */
16608/* Based on ALC880 version. But ALC861VD has separate,
16609 * different NIDs for mute/unmute switch and volume control */
16610static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16611 hda_nid_t pin, const char *pfx)
16612{
16613 hda_nid_t nid_v, nid_s;
16614 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016615
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016616 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016617 return 0;
16618
16619 if (alc880_is_fixed_pin(pin)) {
16620 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16621 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016622 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016623 spec->multiout.hp_nid = nid_v;
16624 else
16625 spec->multiout.extra_out_nid[0] = nid_v;
16626 /* control HP volume/switch on the output mixer amp */
16627 nid_v = alc861vd_idx_to_mixer_vol(
16628 alc880_fixed_pin_idx(pin));
16629 nid_s = alc861vd_idx_to_mixer_switch(
16630 alc880_fixed_pin_idx(pin));
16631
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016632 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016633 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16634 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016635 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016636 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016637 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16638 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016639 return err;
16640 } else if (alc880_is_multi_pin(pin)) {
16641 /* set manual connection */
16642 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016643 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016644 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16645 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016646 return err;
16647 }
16648 return 0;
16649}
16650
16651/* parse the BIOS configuration and set up the alc_spec
16652 * return 1 if successful, 0 if the proper config is not found,
16653 * or a negative error code
16654 * Based on ALC880 version - had to change it to override
16655 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16656static int alc861vd_parse_auto_config(struct hda_codec *codec)
16657{
16658 struct alc_spec *spec = codec->spec;
16659 int err;
16660 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
16661
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016662 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16663 alc861vd_ignore);
16664 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016665 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016666 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016667 return 0; /* can't find valid BIOS pin config */
16668
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016669 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16670 if (err < 0)
16671 return err;
16672 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16673 if (err < 0)
16674 return err;
16675 err = alc861vd_auto_create_extra_out(spec,
16676 spec->autocfg.speaker_pins[0],
16677 "Speaker");
16678 if (err < 0)
16679 return err;
16680 err = alc861vd_auto_create_extra_out(spec,
16681 spec->autocfg.hp_pins[0],
16682 "Headphone");
16683 if (err < 0)
16684 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016685 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016686 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016687 return err;
16688
16689 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16690
Takashi Iwai757899a2010-07-30 10:48:14 +020016691 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016692
Takashi Iwai603c4012008-07-30 15:01:44 +020016693 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016694 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016695
Takashi Iwaid88897e2008-10-31 15:01:37 +010016696 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016697
16698 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016699 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016700
Takashi Iwai776e1842007-08-29 15:07:11 +020016701 err = alc_auto_add_mic_boost(codec);
16702 if (err < 0)
16703 return err;
16704
Kailang Yang6227cdc2010-02-25 08:36:52 +010016705 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016706
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016707 return 1;
16708}
16709
16710/* additional initialization for auto-configuration model */
16711static void alc861vd_auto_init(struct hda_codec *codec)
16712{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016713 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016714 alc861vd_auto_init_multi_out(codec);
16715 alc861vd_auto_init_hp_out(codec);
16716 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016717 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016718 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016719 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016720 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016721}
16722
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016723enum {
16724 ALC660VD_FIX_ASUS_GPIO1
16725};
16726
16727/* reset GPIO1 */
16728static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
16729 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16730 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16731 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16732 { }
16733};
16734
16735static const struct alc_fixup alc861vd_fixups[] = {
16736 [ALC660VD_FIX_ASUS_GPIO1] = {
16737 .verbs = alc660vd_fix_asus_gpio1_verbs,
16738 },
16739};
16740
16741static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
16742 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16743 {}
16744};
16745
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016746static int patch_alc861vd(struct hda_codec *codec)
16747{
16748 struct alc_spec *spec;
16749 int err, board_config;
16750
16751 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16752 if (spec == NULL)
16753 return -ENOMEM;
16754
16755 codec->spec = spec;
16756
16757 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16758 alc861vd_models,
16759 alc861vd_cfg_tbl);
16760
16761 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016762 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16763 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016764 board_config = ALC861VD_AUTO;
16765 }
16766
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016767 if (board_config == ALC861VD_AUTO)
16768 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016769
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016770 if (board_config == ALC861VD_AUTO) {
16771 /* automatic parse from the BIOS config */
16772 err = alc861vd_parse_auto_config(codec);
16773 if (err < 0) {
16774 alc_free(codec);
16775 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016776 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016777 printk(KERN_INFO
16778 "hda_codec: Cannot set up configuration "
16779 "from BIOS. Using base mode...\n");
16780 board_config = ALC861VD_3ST;
16781 }
16782 }
16783
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016784 err = snd_hda_attach_beep_device(codec, 0x23);
16785 if (err < 0) {
16786 alc_free(codec);
16787 return err;
16788 }
16789
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016790 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016791 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016792
Kailang Yang2f893282008-05-27 12:14:47 +020016793 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016794 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016795 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016796 }
16797
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016798 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16799 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16800
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016801 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16802 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16803
Takashi Iwaidd704692009-08-11 08:45:11 +020016804 if (!spec->adc_nids) {
16805 spec->adc_nids = alc861vd_adc_nids;
16806 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16807 }
16808 if (!spec->capsrc_nids)
16809 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016810
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016811 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016812 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016813
Takashi Iwai2134ea42008-01-10 16:53:55 +010016814 spec->vmaster_nid = 0x02;
16815
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016816 if (board_config == ALC861VD_AUTO)
16817 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
16818
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016819 codec->patch_ops = alc_patch_ops;
16820
16821 if (board_config == ALC861VD_AUTO)
16822 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016823#ifdef CONFIG_SND_HDA_POWER_SAVE
16824 if (!spec->loopback.amplist)
16825 spec->loopback.amplist = alc861vd_loopbacks;
16826#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016827
16828 return 0;
16829}
16830
16831/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016832 * ALC662 support
16833 *
16834 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16835 * configuration. Each pin widget can choose any input DACs and a mixer.
16836 * Each ADC is connected from a mixer of all inputs. This makes possible
16837 * 6-channel independent captures.
16838 *
16839 * In addition, an independent DAC for the multi-playback (not used in this
16840 * driver yet).
16841 */
16842#define ALC662_DIGOUT_NID 0x06
16843#define ALC662_DIGIN_NID 0x0a
16844
16845static hda_nid_t alc662_dac_nids[4] = {
16846 /* front, rear, clfe, rear_surr */
16847 0x02, 0x03, 0x04
16848};
16849
Kailang Yang622e84c2009-04-21 07:39:04 +020016850static hda_nid_t alc272_dac_nids[2] = {
16851 0x02, 0x03
16852};
16853
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016854static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016855 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016856 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016857};
Takashi Iwaie1406342008-02-11 18:32:32 +010016858
Kailang Yang622e84c2009-04-21 07:39:04 +020016859static hda_nid_t alc272_adc_nids[1] = {
16860 /* ADC1-2 */
16861 0x08,
16862};
16863
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016864static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016865static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16866
Takashi Iwaie1406342008-02-11 18:32:32 +010016867
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016868/* input MUX */
16869/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016870static struct hda_input_mux alc662_capture_source = {
16871 .num_items = 4,
16872 .items = {
16873 { "Mic", 0x0 },
16874 { "Front Mic", 0x1 },
16875 { "Line", 0x2 },
16876 { "CD", 0x4 },
16877 },
16878};
16879
16880static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16881 .num_items = 2,
16882 .items = {
16883 { "Mic", 0x1 },
16884 { "Line", 0x2 },
16885 },
16886};
Kailang Yang291702f2007-10-16 14:28:03 +020016887
Kailang Yang6dda9f42008-05-27 12:05:31 +020016888static struct hda_input_mux alc663_capture_source = {
16889 .num_items = 3,
16890 .items = {
16891 { "Mic", 0x0 },
16892 { "Front Mic", 0x1 },
16893 { "Line", 0x2 },
16894 },
16895};
16896
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016897#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016898static struct hda_input_mux alc272_nc10_capture_source = {
16899 .num_items = 16,
16900 .items = {
16901 { "Autoselect Mic", 0x0 },
16902 { "Internal Mic", 0x1 },
16903 { "In-0x02", 0x2 },
16904 { "In-0x03", 0x3 },
16905 { "In-0x04", 0x4 },
16906 { "In-0x05", 0x5 },
16907 { "In-0x06", 0x6 },
16908 { "In-0x07", 0x7 },
16909 { "In-0x08", 0x8 },
16910 { "In-0x09", 0x9 },
16911 { "In-0x0a", 0x0a },
16912 { "In-0x0b", 0x0b },
16913 { "In-0x0c", 0x0c },
16914 { "In-0x0d", 0x0d },
16915 { "In-0x0e", 0x0e },
16916 { "In-0x0f", 0x0f },
16917 },
16918};
16919#endif
16920
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016921/*
16922 * 2ch mode
16923 */
16924static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16925 { 2, NULL }
16926};
16927
16928/*
16929 * 2ch mode
16930 */
16931static struct hda_verb alc662_3ST_ch2_init[] = {
16932 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16933 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16934 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16935 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16936 { } /* end */
16937};
16938
16939/*
16940 * 6ch mode
16941 */
16942static struct hda_verb alc662_3ST_ch6_init[] = {
16943 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16944 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16945 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16946 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16947 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16948 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16949 { } /* end */
16950};
16951
16952static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16953 { 2, alc662_3ST_ch2_init },
16954 { 6, alc662_3ST_ch6_init },
16955};
16956
16957/*
16958 * 2ch mode
16959 */
16960static struct hda_verb alc662_sixstack_ch6_init[] = {
16961 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16962 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16963 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16964 { } /* end */
16965};
16966
16967/*
16968 * 6ch mode
16969 */
16970static struct hda_verb alc662_sixstack_ch8_init[] = {
16971 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16972 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16973 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16974 { } /* end */
16975};
16976
16977static struct hda_channel_mode alc662_5stack_modes[2] = {
16978 { 2, alc662_sixstack_ch6_init },
16979 { 6, alc662_sixstack_ch8_init },
16980};
16981
16982/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16983 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16984 */
16985
16986static struct snd_kcontrol_new alc662_base_mixer[] = {
16987 /* output mixer control */
16988 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016989 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016990 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016991 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016992 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16993 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016994 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16995 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016996 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16997
16998 /*Input mixer control */
16999 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17000 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17001 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17002 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17003 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17004 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17005 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17006 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017007 { } /* end */
17008};
17009
17010static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17011 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017012 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017013 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17014 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17015 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17016 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17017 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17018 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17019 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17020 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17021 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017022 { } /* end */
17023};
17024
17025static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17026 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017027 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017028 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017029 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017030 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17031 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017032 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17033 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017034 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17035 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17036 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17037 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17038 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17040 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17041 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17042 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017043 { } /* end */
17044};
17045
17046static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17047 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17048 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017049 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17050 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017051 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17052 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17053 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17054 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17055 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017056 { } /* end */
17057};
17058
Kailang Yang291702f2007-10-16 14:28:03 +020017059static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017060 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17061 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017062
17063 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17064 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17065 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17066
17067 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17068 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17069 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17070 { } /* end */
17071};
17072
Kailang Yang8c427222008-01-10 13:03:59 +010017073static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017074 ALC262_HIPPO_MASTER_SWITCH,
17075 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017076 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017077 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17078 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017079 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17080 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17081 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17082 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17083 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17084 { } /* end */
17085};
17086
Kailang Yangf1d4e282008-08-26 14:03:29 +020017087static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17088 .ops = &snd_hda_bind_vol,
17089 .values = {
17090 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17091 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17092 0
17093 },
17094};
17095
17096static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17097 .ops = &snd_hda_bind_sw,
17098 .values = {
17099 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17100 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17101 0
17102 },
17103};
17104
Kailang Yang6dda9f42008-05-27 12:05:31 +020017105static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017106 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17107 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17108 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17109 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17110 { } /* end */
17111};
17112
17113static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17114 .ops = &snd_hda_bind_sw,
17115 .values = {
17116 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17117 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17118 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17119 0
17120 },
17121};
17122
17123static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17124 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17125 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17126 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17127 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17128 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17129 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17130
17131 { } /* end */
17132};
17133
17134static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17135 .ops = &snd_hda_bind_sw,
17136 .values = {
17137 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17138 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17139 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17140 0
17141 },
17142};
17143
17144static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17145 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17146 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17148 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17149 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17150 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17151 { } /* end */
17152};
17153
17154static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017155 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17156 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017157 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17158 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17159 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17160 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17161 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17162 { } /* end */
17163};
17164
17165static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17166 .ops = &snd_hda_bind_vol,
17167 .values = {
17168 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17169 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17170 0
17171 },
17172};
17173
17174static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17175 .ops = &snd_hda_bind_sw,
17176 .values = {
17177 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17178 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17179 0
17180 },
17181};
17182
17183static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17184 HDA_BIND_VOL("Master Playback Volume",
17185 &alc663_asus_two_bind_master_vol),
17186 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17187 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017188 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17189 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17190 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017191 { } /* end */
17192};
17193
17194static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17195 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17196 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17197 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17199 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17200 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017201 { } /* end */
17202};
17203
17204static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17205 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17206 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17207 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17208 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17209 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17210
17211 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17212 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17213 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17214 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17215 { } /* end */
17216};
17217
17218static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17219 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17220 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17221 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17222
17223 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17224 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17225 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17226 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17227 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17228 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17229 { } /* end */
17230};
17231
Kailang Yangebb83ee2009-12-17 12:23:00 +010017232static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17233 .ops = &snd_hda_bind_sw,
17234 .values = {
17235 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17236 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17237 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17238 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17239 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17240 0
17241 },
17242};
17243
17244static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17245 .ops = &snd_hda_bind_sw,
17246 .values = {
17247 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17248 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17249 0
17250 },
17251};
17252
17253static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17254 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17255 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17256 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17257 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17258 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17259 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17260 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17261 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17262 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17263 { } /* end */
17264};
17265
17266static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17267 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17268 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17269 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17270 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17271 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17272 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17273 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17274 { } /* end */
17275};
17276
17277
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017278static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17279 {
17280 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17281 .name = "Channel Mode",
17282 .info = alc_ch_mode_info,
17283 .get = alc_ch_mode_get,
17284 .put = alc_ch_mode_put,
17285 },
17286 { } /* end */
17287};
17288
17289static struct hda_verb alc662_init_verbs[] = {
17290 /* ADC: mute amp left and right */
17291 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17292 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017293
Kailang Yangb60dd392007-09-20 12:50:29 +020017294 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17295 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17296 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17297 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17298 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17299 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017300
17301 /* Front Pin: output 0 (0x0c) */
17302 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17303 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17304
17305 /* Rear Pin: output 1 (0x0d) */
17306 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17307 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17308
17309 /* CLFE Pin: output 2 (0x0e) */
17310 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17311 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17312
17313 /* Mic (rear) pin: input vref at 80% */
17314 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17315 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17316 /* Front Mic pin: input vref at 80% */
17317 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17318 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17319 /* Line In pin: input */
17320 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17321 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17322 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17323 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17324 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17325 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17326 /* CD pin widget for input */
17327 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17328
17329 /* FIXME: use matrix-type input source selection */
17330 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17331 /* Input mixer */
17332 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017333 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017334
17335 /* always trun on EAPD */
17336 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17337 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17338
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017339 { }
17340};
17341
Kailang Yangcec27c82010-02-04 14:18:18 +010017342static struct hda_verb alc663_init_verbs[] = {
17343 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17344 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17345 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17346 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17347 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17348 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17349 { }
17350};
17351
17352static struct hda_verb alc272_init_verbs[] = {
17353 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17354 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17355 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17356 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17357 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17358 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17359 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17360 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17361 { }
17362};
17363
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017364static struct hda_verb alc662_sue_init_verbs[] = {
17365 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17366 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017367 {}
17368};
17369
17370static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17371 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17372 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17373 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017374};
17375
Kailang Yang8c427222008-01-10 13:03:59 +010017376/* Set Unsolicited Event*/
17377static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17378 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17379 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17380 {}
17381};
17382
Kailang Yang6dda9f42008-05-27 12:05:31 +020017383static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017384 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17385 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017386 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17387 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017388 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17389 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17390 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017391 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17392 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17393 {}
17394};
17395
Kailang Yangf1d4e282008-08-26 14:03:29 +020017396static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17397 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17398 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17399 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17400 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17401 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17402 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17403 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17404 {}
17405};
17406
17407static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17408 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17409 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17410 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17411 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17412 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17413 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17414 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17415 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17416 {}
17417};
17418
17419static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17420 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17421 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17422 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17423 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17424 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17425 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17426 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17427 {}
17428};
17429
17430static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17431 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17432 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17433 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17434 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17435 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17436 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17437 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17438 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17439 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17440 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17441 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17442 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17443 {}
17444};
17445
17446static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17447 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17448 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17449 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17450 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17451 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17452 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17453 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17454 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17455 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17456 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17457 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17458 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17459 {}
17460};
17461
Kailang Yang6dda9f42008-05-27 12:05:31 +020017462static struct hda_verb alc663_g71v_init_verbs[] = {
17463 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17464 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17465 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17466
17467 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17468 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17469 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17470
17471 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17472 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17473 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17474 {}
17475};
17476
17477static struct hda_verb alc663_g50v_init_verbs[] = {
17478 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17479 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17480 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17481
17482 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17483 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17484 {}
17485};
17486
Kailang Yangf1d4e282008-08-26 14:03:29 +020017487static struct hda_verb alc662_ecs_init_verbs[] = {
17488 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17489 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17490 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17491 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17492 {}
17493};
17494
Kailang Yang622e84c2009-04-21 07:39:04 +020017495static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17496 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17497 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17498 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17499 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17500 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17501 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17502 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17503 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17504 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17505 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17506 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17507 {}
17508};
17509
17510static struct hda_verb alc272_dell_init_verbs[] = {
17511 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17512 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17513 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17514 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17515 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17516 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17517 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17518 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17519 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17520 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17521 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17522 {}
17523};
17524
Kailang Yangebb83ee2009-12-17 12:23:00 +010017525static struct hda_verb alc663_mode7_init_verbs[] = {
17526 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17527 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17528 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17529 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17530 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17531 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17532 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17533 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17534 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17535 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17538 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17539 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17540 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17541 {}
17542};
17543
17544static struct hda_verb alc663_mode8_init_verbs[] = {
17545 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17546 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17547 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17548 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17549 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17550 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17551 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17552 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17553 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17554 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17555 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17556 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17557 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17558 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17559 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17560 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17561 {}
17562};
17563
Kailang Yangf1d4e282008-08-26 14:03:29 +020017564static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17565 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17566 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17567 { } /* end */
17568};
17569
Kailang Yang622e84c2009-04-21 07:39:04 +020017570static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17571 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17572 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17573 { } /* end */
17574};
17575
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017576static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17577{
17578 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017579 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017580
Wu Fengguang864f92b2009-11-18 12:38:02 +080017581 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017582 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017583
Takashi Iwai47fd8302007-08-10 17:11:07 +020017584 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17585 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017586}
17587
17588static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17589{
17590 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017591 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017592
Wu Fengguang864f92b2009-11-18 12:38:02 +080017593 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017594 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017595
Takashi Iwai47fd8302007-08-10 17:11:07 +020017596 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17597 HDA_AMP_MUTE, bits);
17598 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17599 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017600}
17601
17602static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17603 unsigned int res)
17604{
17605 if ((res >> 26) == ALC880_HP_EVENT)
17606 alc662_lenovo_101e_all_automute(codec);
17607 if ((res >> 26) == ALC880_FRONT_EVENT)
17608 alc662_lenovo_101e_ispeaker_automute(codec);
17609}
17610
Kailang Yang291702f2007-10-16 14:28:03 +020017611/* unsolicited event for HP jack sensing */
17612static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17613 unsigned int res)
17614{
Kailang Yang291702f2007-10-16 14:28:03 +020017615 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017616 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020017617 else
17618 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020017619}
17620
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017621static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017622{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017623 struct alc_spec *spec = codec->spec;
17624
17625 alc262_hippo1_setup(codec);
17626 spec->ext_mic.pin = 0x18;
17627 spec->ext_mic.mux_idx = 0;
17628 spec->int_mic.pin = 0x19;
17629 spec->int_mic.mux_idx = 1;
17630 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017631}
17632
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017633static void alc662_eeepc_inithook(struct hda_codec *codec)
17634{
17635 alc262_hippo_automute(codec);
17636 alc_mic_automute(codec);
17637}
17638
17639static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017640{
Takashi Iwai42171c12009-05-08 14:11:43 +020017641 struct alc_spec *spec = codec->spec;
17642
17643 spec->autocfg.hp_pins[0] = 0x14;
17644 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010017645}
17646
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017647#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
17648
Kailang Yang6dda9f42008-05-27 12:05:31 +020017649static void alc663_m51va_speaker_automute(struct hda_codec *codec)
17650{
17651 unsigned int present;
17652 unsigned char bits;
17653
Wu Fengguang864f92b2009-11-18 12:38:02 +080017654 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017655 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017656 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017657 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017658 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017659 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017660}
17661
17662static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
17663{
17664 unsigned int present;
17665 unsigned char bits;
17666
Wu Fengguang864f92b2009-11-18 12:38:02 +080017667 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017668 bits = present ? HDA_AMP_MUTE : 0;
17669 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017670 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017671 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017672 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017673 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017674 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017675 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017676 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017677}
17678
17679static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
17680{
17681 unsigned int present;
17682 unsigned char bits;
17683
Wu Fengguang864f92b2009-11-18 12:38:02 +080017684 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017685 bits = present ? HDA_AMP_MUTE : 0;
17686 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017687 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017688 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017689 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017690 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017691 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017692 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017693 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017694}
17695
17696static void alc662_f5z_speaker_automute(struct hda_codec *codec)
17697{
17698 unsigned int present;
17699 unsigned char bits;
17700
Wu Fengguang864f92b2009-11-18 12:38:02 +080017701 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017702 bits = present ? 0 : PIN_OUT;
17703 snd_hda_codec_write(codec, 0x14, 0,
17704 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
17705}
17706
17707static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
17708{
17709 unsigned int present1, present2;
17710
Wu Fengguang864f92b2009-11-18 12:38:02 +080017711 present1 = snd_hda_jack_detect(codec, 0x21);
17712 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017713
17714 if (present1 || present2) {
17715 snd_hda_codec_write_cache(codec, 0x14, 0,
17716 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17717 } else {
17718 snd_hda_codec_write_cache(codec, 0x14, 0,
17719 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17720 }
17721}
17722
17723static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
17724{
17725 unsigned int present1, present2;
17726
Wu Fengguang864f92b2009-11-18 12:38:02 +080017727 present1 = snd_hda_jack_detect(codec, 0x1b);
17728 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017729
17730 if (present1 || present2) {
17731 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017732 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017733 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017734 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017735 } else {
17736 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017737 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017738 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017739 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017740 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020017741}
17742
Kailang Yangebb83ee2009-12-17 12:23:00 +010017743static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
17744{
17745 unsigned int present1, present2;
17746
17747 present1 = snd_hda_codec_read(codec, 0x1b, 0,
17748 AC_VERB_GET_PIN_SENSE, 0)
17749 & AC_PINSENSE_PRESENCE;
17750 present2 = snd_hda_codec_read(codec, 0x21, 0,
17751 AC_VERB_GET_PIN_SENSE, 0)
17752 & AC_PINSENSE_PRESENCE;
17753
17754 if (present1 || present2) {
17755 snd_hda_codec_write_cache(codec, 0x14, 0,
17756 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17757 snd_hda_codec_write_cache(codec, 0x17, 0,
17758 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17759 } else {
17760 snd_hda_codec_write_cache(codec, 0x14, 0,
17761 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17762 snd_hda_codec_write_cache(codec, 0x17, 0,
17763 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17764 }
17765}
17766
17767static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
17768{
17769 unsigned int present1, present2;
17770
17771 present1 = snd_hda_codec_read(codec, 0x21, 0,
17772 AC_VERB_GET_PIN_SENSE, 0)
17773 & AC_PINSENSE_PRESENCE;
17774 present2 = snd_hda_codec_read(codec, 0x15, 0,
17775 AC_VERB_GET_PIN_SENSE, 0)
17776 & AC_PINSENSE_PRESENCE;
17777
17778 if (present1 || present2) {
17779 snd_hda_codec_write_cache(codec, 0x14, 0,
17780 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17781 snd_hda_codec_write_cache(codec, 0x17, 0,
17782 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17783 } else {
17784 snd_hda_codec_write_cache(codec, 0x14, 0,
17785 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17786 snd_hda_codec_write_cache(codec, 0x17, 0,
17787 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17788 }
17789}
17790
Kailang Yang6dda9f42008-05-27 12:05:31 +020017791static void alc663_m51va_unsol_event(struct hda_codec *codec,
17792 unsigned int res)
17793{
17794 switch (res >> 26) {
17795 case ALC880_HP_EVENT:
17796 alc663_m51va_speaker_automute(codec);
17797 break;
17798 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017799 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017800 break;
17801 }
17802}
17803
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017804static void alc663_m51va_setup(struct hda_codec *codec)
17805{
17806 struct alc_spec *spec = codec->spec;
17807 spec->ext_mic.pin = 0x18;
17808 spec->ext_mic.mux_idx = 0;
17809 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017810 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017811 spec->auto_mic = 1;
17812}
17813
Kailang Yang6dda9f42008-05-27 12:05:31 +020017814static void alc663_m51va_inithook(struct hda_codec *codec)
17815{
17816 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017817 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017818}
17819
Kailang Yangf1d4e282008-08-26 14:03:29 +020017820/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017821#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017822
17823static void alc663_mode1_setup(struct hda_codec *codec)
17824{
17825 struct alc_spec *spec = codec->spec;
17826 spec->ext_mic.pin = 0x18;
17827 spec->ext_mic.mux_idx = 0;
17828 spec->int_mic.pin = 0x19;
17829 spec->int_mic.mux_idx = 1;
17830 spec->auto_mic = 1;
17831}
17832
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017833#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017834
Kailang Yangf1d4e282008-08-26 14:03:29 +020017835/* ***************** Mode2 ******************************/
17836static void alc662_mode2_unsol_event(struct hda_codec *codec,
17837 unsigned int res)
17838{
17839 switch (res >> 26) {
17840 case ALC880_HP_EVENT:
17841 alc662_f5z_speaker_automute(codec);
17842 break;
17843 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017844 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017845 break;
17846 }
17847}
17848
Kailang Yangebb83ee2009-12-17 12:23:00 +010017849#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017850
Kailang Yangf1d4e282008-08-26 14:03:29 +020017851static void alc662_mode2_inithook(struct hda_codec *codec)
17852{
17853 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017854 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017855}
17856/* ***************** Mode3 ******************************/
17857static void alc663_mode3_unsol_event(struct hda_codec *codec,
17858 unsigned int res)
17859{
17860 switch (res >> 26) {
17861 case ALC880_HP_EVENT:
17862 alc663_two_hp_m1_speaker_automute(codec);
17863 break;
17864 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017865 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017866 break;
17867 }
17868}
17869
Kailang Yangebb83ee2009-12-17 12:23:00 +010017870#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017871
Kailang Yangf1d4e282008-08-26 14:03:29 +020017872static void alc663_mode3_inithook(struct hda_codec *codec)
17873{
17874 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017875 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017876}
17877/* ***************** Mode4 ******************************/
17878static void alc663_mode4_unsol_event(struct hda_codec *codec,
17879 unsigned int res)
17880{
17881 switch (res >> 26) {
17882 case ALC880_HP_EVENT:
17883 alc663_21jd_two_speaker_automute(codec);
17884 break;
17885 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017886 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017887 break;
17888 }
17889}
17890
Kailang Yangebb83ee2009-12-17 12:23:00 +010017891#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017892
Kailang Yangf1d4e282008-08-26 14:03:29 +020017893static void alc663_mode4_inithook(struct hda_codec *codec)
17894{
17895 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017896 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017897}
17898/* ***************** Mode5 ******************************/
17899static void alc663_mode5_unsol_event(struct hda_codec *codec,
17900 unsigned int res)
17901{
17902 switch (res >> 26) {
17903 case ALC880_HP_EVENT:
17904 alc663_15jd_two_speaker_automute(codec);
17905 break;
17906 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017907 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017908 break;
17909 }
17910}
17911
Kailang Yangebb83ee2009-12-17 12:23:00 +010017912#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017913
Kailang Yangf1d4e282008-08-26 14:03:29 +020017914static void alc663_mode5_inithook(struct hda_codec *codec)
17915{
17916 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017917 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017918}
17919/* ***************** Mode6 ******************************/
17920static void alc663_mode6_unsol_event(struct hda_codec *codec,
17921 unsigned int res)
17922{
17923 switch (res >> 26) {
17924 case ALC880_HP_EVENT:
17925 alc663_two_hp_m2_speaker_automute(codec);
17926 break;
17927 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017928 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017929 break;
17930 }
17931}
17932
Kailang Yangebb83ee2009-12-17 12:23:00 +010017933#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017934
Kailang Yangf1d4e282008-08-26 14:03:29 +020017935static void alc663_mode6_inithook(struct hda_codec *codec)
17936{
17937 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017938 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017939}
17940
Kailang Yangebb83ee2009-12-17 12:23:00 +010017941/* ***************** Mode7 ******************************/
17942static void alc663_mode7_unsol_event(struct hda_codec *codec,
17943 unsigned int res)
17944{
17945 switch (res >> 26) {
17946 case ALC880_HP_EVENT:
17947 alc663_two_hp_m7_speaker_automute(codec);
17948 break;
17949 case ALC880_MIC_EVENT:
17950 alc_mic_automute(codec);
17951 break;
17952 }
17953}
17954
17955#define alc663_mode7_setup alc663_mode1_setup
17956
17957static void alc663_mode7_inithook(struct hda_codec *codec)
17958{
17959 alc663_two_hp_m7_speaker_automute(codec);
17960 alc_mic_automute(codec);
17961}
17962
17963/* ***************** Mode8 ******************************/
17964static void alc663_mode8_unsol_event(struct hda_codec *codec,
17965 unsigned int res)
17966{
17967 switch (res >> 26) {
17968 case ALC880_HP_EVENT:
17969 alc663_two_hp_m8_speaker_automute(codec);
17970 break;
17971 case ALC880_MIC_EVENT:
17972 alc_mic_automute(codec);
17973 break;
17974 }
17975}
17976
17977#define alc663_mode8_setup alc663_m51va_setup
17978
17979static void alc663_mode8_inithook(struct hda_codec *codec)
17980{
17981 alc663_two_hp_m8_speaker_automute(codec);
17982 alc_mic_automute(codec);
17983}
17984
Kailang Yang6dda9f42008-05-27 12:05:31 +020017985static void alc663_g71v_hp_automute(struct hda_codec *codec)
17986{
17987 unsigned int present;
17988 unsigned char bits;
17989
Wu Fengguang864f92b2009-11-18 12:38:02 +080017990 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017991 bits = present ? HDA_AMP_MUTE : 0;
17992 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17993 HDA_AMP_MUTE, bits);
17994 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17995 HDA_AMP_MUTE, bits);
17996}
17997
17998static void alc663_g71v_front_automute(struct hda_codec *codec)
17999{
18000 unsigned int present;
18001 unsigned char bits;
18002
Wu Fengguang864f92b2009-11-18 12:38:02 +080018003 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018004 bits = present ? HDA_AMP_MUTE : 0;
18005 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18006 HDA_AMP_MUTE, bits);
18007}
18008
18009static void alc663_g71v_unsol_event(struct hda_codec *codec,
18010 unsigned int res)
18011{
18012 switch (res >> 26) {
18013 case ALC880_HP_EVENT:
18014 alc663_g71v_hp_automute(codec);
18015 break;
18016 case ALC880_FRONT_EVENT:
18017 alc663_g71v_front_automute(codec);
18018 break;
18019 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018020 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018021 break;
18022 }
18023}
18024
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018025#define alc663_g71v_setup alc663_m51va_setup
18026
Kailang Yang6dda9f42008-05-27 12:05:31 +020018027static void alc663_g71v_inithook(struct hda_codec *codec)
18028{
18029 alc663_g71v_front_automute(codec);
18030 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018031 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018032}
18033
18034static void alc663_g50v_unsol_event(struct hda_codec *codec,
18035 unsigned int res)
18036{
18037 switch (res >> 26) {
18038 case ALC880_HP_EVENT:
18039 alc663_m51va_speaker_automute(codec);
18040 break;
18041 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018042 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018043 break;
18044 }
18045}
18046
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018047#define alc663_g50v_setup alc663_m51va_setup
18048
Kailang Yang6dda9f42008-05-27 12:05:31 +020018049static void alc663_g50v_inithook(struct hda_codec *codec)
18050{
18051 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018052 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018053}
18054
Kailang Yangf1d4e282008-08-26 14:03:29 +020018055static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18056 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018057 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018058
18059 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
18060 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18061 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18062
18063 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18064 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18065 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18066 { } /* end */
18067};
18068
Chris Pockelé9541ba12009-05-12 08:08:53 +020018069static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18070 /* Master Playback automatically created from Speaker and Headphone */
18071 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18072 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18073 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18074 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18075
18076 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18077 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18078 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18079
18080 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18081 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18082 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18083 { } /* end */
18084};
18085
Takashi Iwaicb53c622007-08-10 17:21:45 +020018086#ifdef CONFIG_SND_HDA_POWER_SAVE
18087#define alc662_loopbacks alc880_loopbacks
18088#endif
18089
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018090
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018091/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018092#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18093#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18094#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18095#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18096
18097/*
18098 * configuration and preset
18099 */
18100static const char *alc662_models[ALC662_MODEL_LAST] = {
18101 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18102 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18103 [ALC662_3ST_6ch] = "3stack-6ch",
18104 [ALC662_5ST_DIG] = "6stack-dig",
18105 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018106 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018107 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018108 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018109 [ALC663_ASUS_M51VA] = "m51va",
18110 [ALC663_ASUS_G71V] = "g71v",
18111 [ALC663_ASUS_H13] = "h13",
18112 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018113 [ALC663_ASUS_MODE1] = "asus-mode1",
18114 [ALC662_ASUS_MODE2] = "asus-mode2",
18115 [ALC663_ASUS_MODE3] = "asus-mode3",
18116 [ALC663_ASUS_MODE4] = "asus-mode4",
18117 [ALC663_ASUS_MODE5] = "asus-mode5",
18118 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018119 [ALC663_ASUS_MODE7] = "asus-mode7",
18120 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018121 [ALC272_DELL] = "dell",
18122 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018123 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018124 [ALC662_AUTO] = "auto",
18125};
18126
18127static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018128 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018129 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18130 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018131 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18132 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018133 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018134 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18135 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18136 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18137 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018138 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18139 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018140 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018141 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18142 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18143 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18144 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18145 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018146 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018147 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18148 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018149 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18150 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18151 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18152 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018153 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018154 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18155 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18156 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018157 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18158 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18159 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18160 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018161 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018162 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18163 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018164 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018165 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18166 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18167 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018168 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018169 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018170 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18171 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018172 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18173 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18174 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018175 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018176 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18177 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018178 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018179 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018180 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018181 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18182 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18183 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018184 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018185 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18186 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018187 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018188 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018189 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018190 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018191 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18192 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018193 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018194 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018195 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18196 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018197 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018198 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018199 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018200 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018201 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018202 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018203 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18204 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018205 {}
18206};
18207
18208static struct alc_config_preset alc662_presets[] = {
18209 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018210 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018211 .init_verbs = { alc662_init_verbs },
18212 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18213 .dac_nids = alc662_dac_nids,
18214 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018215 .dig_in_nid = ALC662_DIGIN_NID,
18216 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18217 .channel_mode = alc662_3ST_2ch_modes,
18218 .input_mux = &alc662_capture_source,
18219 },
18220 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018221 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018222 .init_verbs = { alc662_init_verbs },
18223 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18224 .dac_nids = alc662_dac_nids,
18225 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018226 .dig_in_nid = ALC662_DIGIN_NID,
18227 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18228 .channel_mode = alc662_3ST_6ch_modes,
18229 .need_dac_fix = 1,
18230 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018231 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018232 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018233 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018234 .init_verbs = { alc662_init_verbs },
18235 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18236 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018237 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18238 .channel_mode = alc662_3ST_6ch_modes,
18239 .need_dac_fix = 1,
18240 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018241 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018242 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018243 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018244 .init_verbs = { alc662_init_verbs },
18245 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18246 .dac_nids = alc662_dac_nids,
18247 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018248 .dig_in_nid = ALC662_DIGIN_NID,
18249 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18250 .channel_mode = alc662_5stack_modes,
18251 .input_mux = &alc662_capture_source,
18252 },
18253 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018254 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018255 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18256 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18257 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018258 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18259 .channel_mode = alc662_3ST_2ch_modes,
18260 .input_mux = &alc662_lenovo_101e_capture_source,
18261 .unsol_event = alc662_lenovo_101e_unsol_event,
18262 .init_hook = alc662_lenovo_101e_all_automute,
18263 },
Kailang Yang291702f2007-10-16 14:28:03 +020018264 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018265 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018266 .init_verbs = { alc662_init_verbs,
18267 alc662_eeepc_sue_init_verbs },
18268 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18269 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018270 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18271 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018272 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018273 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018274 .init_hook = alc662_eeepc_inithook,
18275 },
Kailang Yang8c427222008-01-10 13:03:59 +010018276 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018277 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018278 alc662_chmode_mixer },
18279 .init_verbs = { alc662_init_verbs,
18280 alc662_eeepc_ep20_sue_init_verbs },
18281 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18282 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018283 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18284 .channel_mode = alc662_3ST_6ch_modes,
18285 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018286 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018287 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018288 .init_hook = alc662_eeepc_ep20_inithook,
18289 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018291 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018292 .init_verbs = { alc662_init_verbs,
18293 alc662_ecs_init_verbs },
18294 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18295 .dac_nids = alc662_dac_nids,
18296 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18297 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018298 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018299 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018300 .init_hook = alc662_eeepc_inithook,
18301 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018302 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018303 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018304 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18305 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18306 .dac_nids = alc662_dac_nids,
18307 .dig_out_nid = ALC662_DIGOUT_NID,
18308 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18309 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018310 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018311 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018312 .init_hook = alc663_m51va_inithook,
18313 },
18314 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018315 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018316 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18317 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18318 .dac_nids = alc662_dac_nids,
18319 .dig_out_nid = ALC662_DIGOUT_NID,
18320 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18321 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018322 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018323 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018324 .init_hook = alc663_g71v_inithook,
18325 },
18326 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018327 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018328 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18329 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18330 .dac_nids = alc662_dac_nids,
18331 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18332 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018333 .unsol_event = alc663_m51va_unsol_event,
18334 .init_hook = alc663_m51va_inithook,
18335 },
18336 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018337 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018338 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18339 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18340 .dac_nids = alc662_dac_nids,
18341 .dig_out_nid = ALC662_DIGOUT_NID,
18342 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18343 .channel_mode = alc662_3ST_6ch_modes,
18344 .input_mux = &alc663_capture_source,
18345 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018346 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018347 .init_hook = alc663_g50v_inithook,
18348 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018349 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018350 .mixers = { alc663_m51va_mixer },
18351 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018352 .init_verbs = { alc662_init_verbs,
18353 alc663_21jd_amic_init_verbs },
18354 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18355 .hp_nid = 0x03,
18356 .dac_nids = alc662_dac_nids,
18357 .dig_out_nid = ALC662_DIGOUT_NID,
18358 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18359 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018360 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018361 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018362 .init_hook = alc663_mode1_inithook,
18363 },
18364 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018365 .mixers = { alc662_1bjd_mixer },
18366 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018367 .init_verbs = { alc662_init_verbs,
18368 alc662_1bjd_amic_init_verbs },
18369 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18370 .dac_nids = alc662_dac_nids,
18371 .dig_out_nid = ALC662_DIGOUT_NID,
18372 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18373 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018374 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018375 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018376 .init_hook = alc662_mode2_inithook,
18377 },
18378 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018379 .mixers = { alc663_two_hp_m1_mixer },
18380 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018381 .init_verbs = { alc662_init_verbs,
18382 alc663_two_hp_amic_m1_init_verbs },
18383 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18384 .hp_nid = 0x03,
18385 .dac_nids = alc662_dac_nids,
18386 .dig_out_nid = ALC662_DIGOUT_NID,
18387 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18388 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018389 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018390 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018391 .init_hook = alc663_mode3_inithook,
18392 },
18393 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018394 .mixers = { alc663_asus_21jd_clfe_mixer },
18395 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018396 .init_verbs = { alc662_init_verbs,
18397 alc663_21jd_amic_init_verbs},
18398 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18399 .hp_nid = 0x03,
18400 .dac_nids = alc662_dac_nids,
18401 .dig_out_nid = ALC662_DIGOUT_NID,
18402 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18403 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018404 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018405 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018406 .init_hook = alc663_mode4_inithook,
18407 },
18408 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018409 .mixers = { alc663_asus_15jd_clfe_mixer },
18410 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018411 .init_verbs = { alc662_init_verbs,
18412 alc663_15jd_amic_init_verbs },
18413 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18414 .hp_nid = 0x03,
18415 .dac_nids = alc662_dac_nids,
18416 .dig_out_nid = ALC662_DIGOUT_NID,
18417 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18418 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018419 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018420 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018421 .init_hook = alc663_mode5_inithook,
18422 },
18423 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018424 .mixers = { alc663_two_hp_m2_mixer },
18425 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018426 .init_verbs = { alc662_init_verbs,
18427 alc663_two_hp_amic_m2_init_verbs },
18428 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18429 .hp_nid = 0x03,
18430 .dac_nids = alc662_dac_nids,
18431 .dig_out_nid = ALC662_DIGOUT_NID,
18432 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18433 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018434 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018435 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018436 .init_hook = alc663_mode6_inithook,
18437 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018438 [ALC663_ASUS_MODE7] = {
18439 .mixers = { alc663_mode7_mixer },
18440 .cap_mixer = alc662_auto_capture_mixer,
18441 .init_verbs = { alc662_init_verbs,
18442 alc663_mode7_init_verbs },
18443 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18444 .hp_nid = 0x03,
18445 .dac_nids = alc662_dac_nids,
18446 .dig_out_nid = ALC662_DIGOUT_NID,
18447 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18448 .channel_mode = alc662_3ST_2ch_modes,
18449 .unsol_event = alc663_mode7_unsol_event,
18450 .setup = alc663_mode7_setup,
18451 .init_hook = alc663_mode7_inithook,
18452 },
18453 [ALC663_ASUS_MODE8] = {
18454 .mixers = { alc663_mode8_mixer },
18455 .cap_mixer = alc662_auto_capture_mixer,
18456 .init_verbs = { alc662_init_verbs,
18457 alc663_mode8_init_verbs },
18458 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18459 .hp_nid = 0x03,
18460 .dac_nids = alc662_dac_nids,
18461 .dig_out_nid = ALC662_DIGOUT_NID,
18462 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18463 .channel_mode = alc662_3ST_2ch_modes,
18464 .unsol_event = alc663_mode8_unsol_event,
18465 .setup = alc663_mode8_setup,
18466 .init_hook = alc663_mode8_inithook,
18467 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018468 [ALC272_DELL] = {
18469 .mixers = { alc663_m51va_mixer },
18470 .cap_mixer = alc272_auto_capture_mixer,
18471 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18472 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18473 .dac_nids = alc662_dac_nids,
18474 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18475 .adc_nids = alc272_adc_nids,
18476 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18477 .capsrc_nids = alc272_capsrc_nids,
18478 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018479 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018480 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018481 .init_hook = alc663_m51va_inithook,
18482 },
18483 [ALC272_DELL_ZM1] = {
18484 .mixers = { alc663_m51va_mixer },
18485 .cap_mixer = alc662_auto_capture_mixer,
18486 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18487 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18488 .dac_nids = alc662_dac_nids,
18489 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18490 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018491 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018492 .capsrc_nids = alc662_capsrc_nids,
18493 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018494 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018495 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018496 .init_hook = alc663_m51va_inithook,
18497 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018498 [ALC272_SAMSUNG_NC10] = {
18499 .mixers = { alc272_nc10_mixer },
18500 .init_verbs = { alc662_init_verbs,
18501 alc663_21jd_amic_init_verbs },
18502 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18503 .dac_nids = alc272_dac_nids,
18504 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18505 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018506 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018507 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018508 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018509 .init_hook = alc663_mode4_inithook,
18510 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018511};
18512
18513
18514/*
18515 * BIOS auto configuration
18516 */
18517
Takashi Iwai7085ec12009-10-02 09:03:58 +020018518/* convert from MIX nid to DAC */
18519static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18520{
18521 if (nid == 0x0f)
18522 return 0x02;
18523 else if (nid >= 0x0c && nid <= 0x0e)
18524 return nid - 0x0c + 0x02;
18525 else
18526 return 0;
18527}
18528
18529/* get MIX nid connected to the given pin targeted to DAC */
18530static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18531 hda_nid_t dac)
18532{
18533 hda_nid_t mix[4];
18534 int i, num;
18535
18536 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18537 for (i = 0; i < num; i++) {
18538 if (alc662_mix_to_dac(mix[i]) == dac)
18539 return mix[i];
18540 }
18541 return 0;
18542}
18543
18544/* look for an empty DAC slot */
18545static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18546{
18547 struct alc_spec *spec = codec->spec;
18548 hda_nid_t srcs[5];
18549 int i, j, num;
18550
18551 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18552 if (num < 0)
18553 return 0;
18554 for (i = 0; i < num; i++) {
18555 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18556 if (!nid)
18557 continue;
18558 for (j = 0; j < spec->multiout.num_dacs; j++)
18559 if (spec->multiout.dac_nids[j] == nid)
18560 break;
18561 if (j >= spec->multiout.num_dacs)
18562 return nid;
18563 }
18564 return 0;
18565}
18566
18567/* fill in the dac_nids table from the parsed pin configuration */
18568static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18569 const struct auto_pin_cfg *cfg)
18570{
18571 struct alc_spec *spec = codec->spec;
18572 int i;
18573 hda_nid_t dac;
18574
18575 spec->multiout.dac_nids = spec->private_dac_nids;
18576 for (i = 0; i < cfg->line_outs; i++) {
18577 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18578 if (!dac)
18579 continue;
18580 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18581 }
18582 return 0;
18583}
18584
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018585static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018586 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018587{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018588 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018589 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18590}
18591
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018592static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018593 hda_nid_t nid, unsigned int chs)
18594{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018595 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018596 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18597}
18598
18599#define alc662_add_stereo_vol(spec, pfx, nid) \
18600 alc662_add_vol_ctl(spec, pfx, nid, 3)
18601#define alc662_add_stereo_sw(spec, pfx, nid) \
18602 alc662_add_sw_ctl(spec, pfx, nid, 3)
18603
18604/* add playback controls from the parsed DAC table */
18605static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18606 const struct auto_pin_cfg *cfg)
18607{
18608 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018609 static const char *chname[4] = {
18610 "Front", "Surround", NULL /*CLFE*/, "Side"
18611 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018612 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018613 int i, err;
18614
18615 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018616 nid = spec->multiout.dac_nids[i];
18617 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018618 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018619 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
18620 if (!mix)
18621 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018622 if (i == 2) {
18623 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018624 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018625 if (err < 0)
18626 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018627 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018628 if (err < 0)
18629 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018630 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018631 if (err < 0)
18632 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018633 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018634 if (err < 0)
18635 return err;
18636 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018637 const char *pfx;
18638 if (cfg->line_outs == 1 &&
18639 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018640 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018641 pfx = "Speaker";
18642 else
18643 pfx = "PCM";
18644 } else
18645 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018646 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018647 if (err < 0)
18648 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018649 if (cfg->line_outs == 1 &&
18650 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
18651 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020018652 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018653 if (err < 0)
18654 return err;
18655 }
18656 }
18657 return 0;
18658}
18659
18660/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018661/* return DAC nid if any new DAC is assigned */
18662static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018663 const char *pfx)
18664{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018665 struct alc_spec *spec = codec->spec;
18666 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018667 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018668
18669 if (!pin)
18670 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018671 nid = alc662_look_for_dac(codec, pin);
18672 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018673 /* the corresponding DAC is already occupied */
18674 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18675 return 0; /* no way */
18676 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018677 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018678 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18679 }
18680
18681 mix = alc662_dac_to_mix(codec, pin, nid);
18682 if (!mix)
18683 return 0;
18684 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
18685 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018686 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018687 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
18688 if (err < 0)
18689 return err;
18690 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018691}
18692
18693/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018694#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018695 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018696
18697static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
18698 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018699 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018700{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018701 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020018702 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018703
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018704 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018705 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018706 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
18707 if (num <= 1)
18708 return;
18709 for (i = 0; i < num; i++) {
18710 if (alc662_mix_to_dac(srcs[i]) != dac)
18711 continue;
18712 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18713 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018714 }
18715}
18716
18717static void alc662_auto_init_multi_out(struct hda_codec *codec)
18718{
18719 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018720 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018721 int i;
18722
18723 for (i = 0; i <= HDA_SIDE; i++) {
18724 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18725 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020018726 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018727 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018728 }
18729}
18730
18731static void alc662_auto_init_hp_out(struct hda_codec *codec)
18732{
18733 struct alc_spec *spec = codec->spec;
18734 hda_nid_t pin;
18735
18736 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018737 if (pin)
18738 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
18739 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018740 pin = spec->autocfg.speaker_pins[0];
18741 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018742 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
18743 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018744}
18745
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018746#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
18747
18748static void alc662_auto_init_analog_input(struct hda_codec *codec)
18749{
18750 struct alc_spec *spec = codec->spec;
18751 int i;
18752
18753 for (i = 0; i < AUTO_PIN_LAST; i++) {
18754 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020018755 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010018756 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010018757 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010018758 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018759 snd_hda_codec_write(codec, nid, 0,
18760 AC_VERB_SET_AMP_GAIN_MUTE,
18761 AMP_OUT_MUTE);
18762 }
18763 }
18764}
18765
Takashi Iwaif511b012008-08-15 16:46:42 +020018766#define alc662_auto_init_input_src alc882_auto_init_input_src
18767
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018768static int alc662_parse_auto_config(struct hda_codec *codec)
18769{
18770 struct alc_spec *spec = codec->spec;
18771 int err;
18772 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
18773
18774 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18775 alc662_ignore);
18776 if (err < 0)
18777 return err;
18778 if (!spec->autocfg.line_outs)
18779 return 0; /* can't find valid BIOS pin config */
18780
Takashi Iwai7085ec12009-10-02 09:03:58 +020018781 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018782 if (err < 0)
18783 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018784 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018785 if (err < 0)
18786 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018787 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018788 spec->autocfg.speaker_pins[0],
18789 "Speaker");
18790 if (err < 0)
18791 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018792 if (err)
18793 spec->multiout.extra_out_nid[0] = err;
18794 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018795 "Headphone");
18796 if (err < 0)
18797 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018798 if (err)
18799 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018800 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018801 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018802 return err;
18803
18804 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18805
Takashi Iwai757899a2010-07-30 10:48:14 +020018806 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018807
Takashi Iwai603c4012008-07-30 15:01:44 +020018808 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018809 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018810
18811 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018812 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018813
Kailang Yangcec27c82010-02-04 14:18:18 +010018814 add_verb(spec, alc662_init_verbs);
18815 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018816 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010018817 add_verb(spec, alc663_init_verbs);
18818
18819 if (codec->vendor_id == 0x10ec0272)
18820 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018821
18822 err = alc_auto_add_mic_boost(codec);
18823 if (err < 0)
18824 return err;
18825
Kailang Yang6227cdc2010-02-25 08:36:52 +010018826 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18827 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18828 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18829 else
18830 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018831
Takashi Iwai8c87286f2007-06-19 12:11:16 +020018832 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018833}
18834
18835/* additional initialization for auto-configuration model */
18836static void alc662_auto_init(struct hda_codec *codec)
18837{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018838 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018839 alc662_auto_init_multi_out(codec);
18840 alc662_auto_init_hp_out(codec);
18841 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018842 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020018843 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018844 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018845 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018846}
18847
18848static int patch_alc662(struct hda_codec *codec)
18849{
18850 struct alc_spec *spec;
18851 int err, board_config;
18852
18853 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18854 if (!spec)
18855 return -ENOMEM;
18856
18857 codec->spec = spec;
18858
Kailang Yangda00c242010-03-19 11:23:45 +010018859 alc_auto_parse_customize_define(codec);
18860
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018861 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18862
Kailang Yangc027ddc2010-03-19 11:33:06 +010018863 if (alc_read_coef_idx(codec, 0) == 0x8020)
18864 alc_codec_rename(codec, "ALC661");
18865 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
18866 codec->bus->pci->subsystem_vendor == 0x1025 &&
18867 spec->cdefine.platform_type == 1)
18868 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010018869
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018870 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18871 alc662_models,
18872 alc662_cfg_tbl);
18873 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018874 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18875 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018876 board_config = ALC662_AUTO;
18877 }
18878
18879 if (board_config == ALC662_AUTO) {
18880 /* automatic parse from the BIOS config */
18881 err = alc662_parse_auto_config(codec);
18882 if (err < 0) {
18883 alc_free(codec);
18884 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020018885 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018886 printk(KERN_INFO
18887 "hda_codec: Cannot set up configuration "
18888 "from BIOS. Using base mode...\n");
18889 board_config = ALC662_3ST_2ch_DIG;
18890 }
18891 }
18892
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018893 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020018894 err = snd_hda_attach_beep_device(codec, 0x1);
18895 if (err < 0) {
18896 alc_free(codec);
18897 return err;
18898 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018899 }
18900
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018901 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018902 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018903
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018904 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18905 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18906
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018907 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18908 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18909
Takashi Iwaidd704692009-08-11 08:45:11 +020018910 if (!spec->adc_nids) {
18911 spec->adc_nids = alc662_adc_nids;
18912 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18913 }
18914 if (!spec->capsrc_nids)
18915 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018916
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018917 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018918 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018919
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018920 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010018921 switch (codec->vendor_id) {
18922 case 0x10ec0662:
18923 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18924 break;
18925 case 0x10ec0272:
18926 case 0x10ec0663:
18927 case 0x10ec0665:
18928 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18929 break;
18930 case 0x10ec0273:
18931 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18932 break;
18933 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018934 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018935 spec->vmaster_nid = 0x02;
18936
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018937 codec->patch_ops = alc_patch_ops;
18938 if (board_config == ALC662_AUTO)
18939 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018940#ifdef CONFIG_SND_HDA_POWER_SAVE
18941 if (!spec->loopback.amplist)
18942 spec->loopback.amplist = alc662_loopbacks;
18943#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018944
18945 return 0;
18946}
18947
Kailang Yang274693f2009-12-03 10:07:50 +010018948static int patch_alc888(struct hda_codec *codec)
18949{
18950 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18951 kfree(codec->chip_name);
18952 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018953 if (!codec->chip_name) {
18954 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018955 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018956 }
18957 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018958 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018959 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018960}
18961
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018962/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018963 * ALC680 support
18964 */
18965#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
18966#define alc680_modes alc260_modes
18967
18968static hda_nid_t alc680_dac_nids[3] = {
18969 /* Lout1, Lout2, hp */
18970 0x02, 0x03, 0x04
18971};
18972
18973static hda_nid_t alc680_adc_nids[3] = {
18974 /* ADC0-2 */
18975 /* DMIC, MIC, Line-in*/
18976 0x07, 0x08, 0x09
18977};
18978
18979static struct snd_kcontrol_new alc680_base_mixer[] = {
18980 /* output mixer control */
18981 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
18982 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18983 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
18984 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
18985 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
18986 { }
18987};
18988
18989static struct snd_kcontrol_new alc680_capture_mixer[] = {
18990 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
18991 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
18992 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
18993 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
18994 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
18995 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
18996 { } /* end */
18997};
18998
18999/*
19000 * generic initialization of ADC, input mixers and output mixers
19001 */
19002static struct hda_verb alc680_init_verbs[] = {
19003 /* Unmute DAC0-1 and set vol = 0 */
19004 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
19005 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
19006 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
19007
19008 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19009 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19010 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
19011 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
19012 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
19013
19014 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19015 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19016 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19017 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19018 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19019 { }
19020};
19021
19022/* create input playback/capture controls for the given pin */
19023static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19024 const char *ctlname, int idx)
19025{
19026 hda_nid_t dac;
19027 int err;
19028
19029 switch (nid) {
19030 case 0x14:
19031 dac = 0x02;
19032 break;
19033 case 0x15:
19034 dac = 0x03;
19035 break;
19036 case 0x16:
19037 dac = 0x04;
19038 break;
19039 default:
19040 return 0;
19041 }
19042 if (spec->multiout.dac_nids[0] != dac &&
19043 spec->multiout.dac_nids[1] != dac) {
19044 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19045 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19046 HDA_OUTPUT));
19047 if (err < 0)
19048 return err;
19049
19050 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19051 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19052
19053 if (err < 0)
19054 return err;
19055 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19056 }
19057
19058 return 0;
19059}
19060
19061/* add playback controls from the parsed DAC table */
19062static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19063 const struct auto_pin_cfg *cfg)
19064{
19065 hda_nid_t nid;
19066 int err;
19067
19068 spec->multiout.dac_nids = spec->private_dac_nids;
19069
19070 nid = cfg->line_out_pins[0];
19071 if (nid) {
19072 const char *name;
19073 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19074 name = "Speaker";
19075 else
19076 name = "Front";
19077 err = alc680_new_analog_output(spec, nid, name, 0);
19078 if (err < 0)
19079 return err;
19080 }
19081
19082 nid = cfg->speaker_pins[0];
19083 if (nid) {
19084 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19085 if (err < 0)
19086 return err;
19087 }
19088 nid = cfg->hp_pins[0];
19089 if (nid) {
19090 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19091 if (err < 0)
19092 return err;
19093 }
19094
19095 return 0;
19096}
19097
19098static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19099 hda_nid_t nid, int pin_type)
19100{
19101 alc_set_pin_output(codec, nid, pin_type);
19102}
19103
19104static void alc680_auto_init_multi_out(struct hda_codec *codec)
19105{
19106 struct alc_spec *spec = codec->spec;
19107 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19108 if (nid) {
19109 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19110 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19111 }
19112}
19113
19114static void alc680_auto_init_hp_out(struct hda_codec *codec)
19115{
19116 struct alc_spec *spec = codec->spec;
19117 hda_nid_t pin;
19118
19119 pin = spec->autocfg.hp_pins[0];
19120 if (pin)
19121 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19122 pin = spec->autocfg.speaker_pins[0];
19123 if (pin)
19124 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19125}
19126
19127/* pcm configuration: identical with ALC880 */
19128#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19129#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19130#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19131#define alc680_pcm_digital_playback alc880_pcm_digital_playback
19132
19133static struct hda_input_mux alc680_capture_source = {
19134 .num_items = 1,
19135 .items = {
19136 { "Mic", 0x0 },
19137 },
19138};
19139
19140/*
19141 * BIOS auto configuration
19142 */
19143static int alc680_parse_auto_config(struct hda_codec *codec)
19144{
19145 struct alc_spec *spec = codec->spec;
19146 int err;
19147 static hda_nid_t alc680_ignore[] = { 0 };
19148
19149 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19150 alc680_ignore);
19151 if (err < 0)
19152 return err;
19153 if (!spec->autocfg.line_outs) {
19154 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19155 spec->multiout.max_channels = 2;
19156 spec->no_analog = 1;
19157 goto dig_only;
19158 }
19159 return 0; /* can't find valid BIOS pin config */
19160 }
19161 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19162 if (err < 0)
19163 return err;
19164
19165 spec->multiout.max_channels = 2;
19166
19167 dig_only:
19168 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019169 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019170 if (spec->kctls.list)
19171 add_mixer(spec, spec->kctls.list);
19172
19173 add_verb(spec, alc680_init_verbs);
19174 spec->num_mux_defs = 1;
19175 spec->input_mux = &alc680_capture_source;
19176
19177 err = alc_auto_add_mic_boost(codec);
19178 if (err < 0)
19179 return err;
19180
19181 return 1;
19182}
19183
19184#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19185
19186/* init callback for auto-configuration model -- overriding the default init */
19187static void alc680_auto_init(struct hda_codec *codec)
19188{
19189 struct alc_spec *spec = codec->spec;
19190 alc680_auto_init_multi_out(codec);
19191 alc680_auto_init_hp_out(codec);
19192 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019193 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019194 if (spec->unsol_event)
19195 alc_inithook(codec);
19196}
19197
19198/*
19199 * configuration and preset
19200 */
19201static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019202 [ALC680_BASE] = "base",
19203 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019204};
19205
19206static struct snd_pci_quirk alc680_cfg_tbl[] = {
19207 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19208 {}
19209};
19210
19211static struct alc_config_preset alc680_presets[] = {
19212 [ALC680_BASE] = {
19213 .mixers = { alc680_base_mixer },
19214 .cap_mixer = alc680_capture_mixer,
19215 .init_verbs = { alc680_init_verbs },
19216 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19217 .dac_nids = alc680_dac_nids,
19218 .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
19219 .adc_nids = alc680_adc_nids,
19220 .hp_nid = 0x04,
19221 .dig_out_nid = ALC680_DIGOUT_NID,
19222 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19223 .channel_mode = alc680_modes,
19224 .input_mux = &alc680_capture_source,
19225 },
19226};
19227
19228static int patch_alc680(struct hda_codec *codec)
19229{
19230 struct alc_spec *spec;
19231 int board_config;
19232 int err;
19233
19234 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19235 if (spec == NULL)
19236 return -ENOMEM;
19237
19238 codec->spec = spec;
19239
19240 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19241 alc680_models,
19242 alc680_cfg_tbl);
19243
19244 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19245 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19246 codec->chip_name);
19247 board_config = ALC680_AUTO;
19248 }
19249
19250 if (board_config == ALC680_AUTO) {
19251 /* automatic parse from the BIOS config */
19252 err = alc680_parse_auto_config(codec);
19253 if (err < 0) {
19254 alc_free(codec);
19255 return err;
19256 } else if (!err) {
19257 printk(KERN_INFO
19258 "hda_codec: Cannot set up configuration "
19259 "from BIOS. Using base mode...\n");
19260 board_config = ALC680_BASE;
19261 }
19262 }
19263
19264 if (board_config != ALC680_AUTO)
19265 setup_preset(codec, &alc680_presets[board_config]);
19266
19267 spec->stream_analog_playback = &alc680_pcm_analog_playback;
19268 spec->stream_analog_capture = &alc680_pcm_analog_capture;
19269 spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
19270 spec->stream_digital_playback = &alc680_pcm_digital_playback;
19271
19272 if (!spec->adc_nids) {
19273 spec->adc_nids = alc680_adc_nids;
19274 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19275 }
19276
19277 if (!spec->cap_mixer)
19278 set_capture_mixer(codec);
19279
19280 spec->vmaster_nid = 0x02;
19281
19282 codec->patch_ops = alc_patch_ops;
19283 if (board_config == ALC680_AUTO)
19284 spec->init_hook = alc680_auto_init;
19285
19286 return 0;
19287}
19288
19289/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019290 * patch entries
19291 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019292static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019293 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019294 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019295 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019296 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019297 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019298 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019299 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019300 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019301 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019302 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019303 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19304 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19305 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019306 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019307 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019308 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19309 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019310 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019311 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019312 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019313 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019314 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019315 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019316 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019317 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019318 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019319 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019320 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019321 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019322 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019323 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019324 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019325 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019326 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019327 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019328 {} /* terminator */
19329};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019330
19331MODULE_ALIAS("snd-hda-codec-id:10ec*");
19332
19333MODULE_LICENSE("GPL");
19334MODULE_DESCRIPTION("Realtek HD-audio codec");
19335
19336static struct hda_codec_preset_list realtek_list = {
19337 .preset = snd_hda_preset_realtek,
19338 .owner = THIS_MODULE,
19339};
19340
19341static int __init patch_realtek_init(void)
19342{
19343 return snd_hda_add_codec_preset(&realtek_list);
19344}
19345
19346static void __exit patch_realtek_exit(void)
19347{
19348 snd_hda_delete_codec_preset(&realtek_list);
19349}
19350
19351module_init(patch_realtek_init)
19352module_exit(patch_realtek_exit)