blob: 6c588ef26685dd011f757ea9057725f852373ce6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010081 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010082#ifdef CONFIG_SND_DEBUG
83 ALC260_TEST,
84#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010085 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020086 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Kailang Yangdf694da2005-12-05 19:42:22 +010089/* ALC262 models */
90enum {
91 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020092 ALC262_HIPPO,
93 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010094 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020095 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010096 ALC262_HP_BPC_D7000_WL,
97 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010098 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010099 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200100 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200101 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200102 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200103 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100104 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200105 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200106 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200107 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000108 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100109 ALC262_AUTO,
110 ALC262_MODEL_LAST /* last tag */
111};
112
Kailang Yanga361d842007-06-05 12:30:55 +0200113/* ALC268 models */
114enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200115 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200116 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200117 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200118 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100119 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200120 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100121 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100122 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100123#ifdef CONFIG_SND_DEBUG
124 ALC268_TEST,
125#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200126 ALC268_AUTO,
127 ALC268_MODEL_LAST /* last tag */
128};
129
Kailang Yangf6a92242007-12-13 16:52:54 +0100130/* ALC269 models */
131enum {
132 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200133 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100134 ALC269_AMIC,
135 ALC269_DMIC,
136 ALC269VB_AMIC,
137 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100138 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000139 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100140 ALC269_AUTO,
141 ALC269_MODEL_LAST /* last tag */
142};
143
Kailang Yangdf694da2005-12-05 19:42:22 +0100144/* ALC861 models */
145enum {
146 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200147 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100148 ALC861_3ST_DIG,
149 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200150 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200151 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200152 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100153 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100154 ALC861_AUTO,
155 ALC861_MODEL_LAST,
156};
157
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100158/* ALC861-VD models */
159enum {
160 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200161 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100162 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100163 ALC861VD_3ST,
164 ALC861VD_3ST_DIG,
165 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200166 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200167 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200168 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100169 ALC861VD_AUTO,
170 ALC861VD_MODEL_LAST,
171};
172
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200173/* ALC662 models */
174enum {
175 ALC662_3ST_2ch_DIG,
176 ALC662_3ST_6ch_DIG,
177 ALC662_3ST_6ch,
178 ALC662_5ST_DIG,
179 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200180 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100181 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200182 ALC663_ASUS_M51VA,
183 ALC663_ASUS_G71V,
184 ALC663_ASUS_H13,
185 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200186 ALC662_ECS,
187 ALC663_ASUS_MODE1,
188 ALC662_ASUS_MODE2,
189 ALC663_ASUS_MODE3,
190 ALC663_ASUS_MODE4,
191 ALC663_ASUS_MODE5,
192 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100193 ALC663_ASUS_MODE7,
194 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200195 ALC272_DELL,
196 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200197 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200198 ALC662_AUTO,
199 ALC662_MODEL_LAST,
200};
201
Kailang Yangdf694da2005-12-05 19:42:22 +0100202/* ALC882 models */
203enum {
204 ALC882_3ST_DIG,
205 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200206 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200207 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200208 ALC882_TARGA,
209 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200210 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100211 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800212 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200213 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200214 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100215 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200216 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800217 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200218 ALC883_3ST_2ch_DIG,
219 ALC883_3ST_6ch_DIG,
220 ALC883_3ST_6ch,
221 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200222 ALC883_TARGA_DIG,
223 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200224 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200225 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200226 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800227 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100228 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200229 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200230 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200231 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200232 ALC883_MEDION_MD2,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200233 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100234 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200235 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200236 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200237 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200238 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200239 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200240 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100241 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100242 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430243 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100244 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100245 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800246 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200247 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200248 ALC889A_INTEL,
249 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200250 ALC888_ASUS_M90V,
251 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200252 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100253 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200254 ALC883_SONY_VAIO_TT,
Takashi Iwai4953550a2009-06-30 15:28:30 +0200255 ALC882_AUTO,
256 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200257};
258
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200259/* ALC680 models */
260enum {
261 ALC680_BASE,
262 ALC680_AUTO,
263 ALC680_MODEL_LAST,
264};
265
Kailang Yangdf694da2005-12-05 19:42:22 +0100266/* for GPIO Poll */
267#define GPIO_MASK 0x03
268
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200269/* extra amp-initialization sequence types */
270enum {
271 ALC_INIT_NONE,
272 ALC_INIT_DEFAULT,
273 ALC_INIT_GPIO1,
274 ALC_INIT_GPIO2,
275 ALC_INIT_GPIO3,
276};
277
Takashi Iwai6c819492009-08-10 18:47:44 +0200278struct alc_mic_route {
279 hda_nid_t pin;
280 unsigned char mux_idx;
281 unsigned char amix_idx;
282};
283
284#define MUX_IDX_UNDEF ((unsigned char)-1)
285
Kailang Yangda00c242010-03-19 11:23:45 +0100286struct alc_customize_define {
287 unsigned int sku_cfg;
288 unsigned char port_connectivity;
289 unsigned char check_sum;
290 unsigned char customization;
291 unsigned char external_amp;
292 unsigned int enable_pcbeep:1;
293 unsigned int platform_type:1;
294 unsigned int swap:1;
295 unsigned int override:1;
296};
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298struct alc_spec {
299 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100300 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100302 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100303 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200305 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200306 * don't forget NULL
307 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200308 */
309 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200311 char stream_name_analog[32]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct hda_pcm_stream *stream_analog_playback;
313 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100314 struct hda_pcm_stream *stream_analog_alt_playback;
315 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200317 char stream_name_digital[32]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 struct hda_pcm_stream *stream_digital_playback;
319 struct hda_pcm_stream *stream_digital_capture;
320
321 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200322 struct hda_multi_out multiout; /* playback set-up
323 * max_channels, dacs must be set
324 * dig_out_nid and hp_nid are optional
325 */
Takashi Iwai63300792008-01-24 15:31:36 +0100326 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100327 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100328 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 /* capture */
331 unsigned int num_adc_nids;
332 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100333 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200334 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Takashi Iwai840b64c2010-07-13 22:49:01 +0200336 /* capture setup for dynamic dual-adc switch */
337 unsigned int cur_adc_idx;
338 hda_nid_t cur_adc;
339 unsigned int cur_adc_stream_tag;
340 unsigned int cur_adc_format;
341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200343 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 const struct hda_input_mux *input_mux;
345 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200346 struct alc_mic_route ext_mic;
347 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100350 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200352 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200353 int const_channel_count;
354 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100357 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200358
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200359 /* dynamic controls, init_verbs and input_mux */
360 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100361 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200362 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200363 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200364 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai4953550a2009-06-30 15:28:30 +0200365 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
366 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100367
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100368 /* hooks */
369 void (*init_hook)(struct hda_codec *codec);
370 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100371#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500372 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100373#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100374
Takashi Iwai834be882006-03-01 14:16:17 +0100375 /* for pin sensing */
376 unsigned int sense_updated: 1;
377 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100378 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200379 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200380
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100381 /* other flags */
382 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200383 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200384 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100385
Takashi Iwai2134ea42008-01-10 16:53:55 +0100386 /* for virtual master */
387 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200388#ifdef CONFIG_SND_HDA_POWER_SAVE
389 struct hda_loopback_check loopback;
390#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200391
392 /* for PLL fix */
393 hda_nid_t pll_nid;
394 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100395};
396
397/*
398 * configuration template - to be copied to the spec instance
399 */
400struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200401 struct snd_kcontrol_new *mixers[5]; /* should be identical size
402 * with spec
403 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100404 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100405 const struct hda_verb *init_verbs[5];
406 unsigned int num_dacs;
407 hda_nid_t *dac_nids;
408 hda_nid_t dig_out_nid; /* optional */
409 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800410 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100411 unsigned int num_adc_nids;
412 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100413 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100414 hda_nid_t dig_in_nid;
415 unsigned int num_channel_mode;
416 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200417 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200418 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200419 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100420 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100421 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200422 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100423 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200424#ifdef CONFIG_SND_HDA_POWER_SAVE
425 struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500426 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200427#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428};
429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431/*
432 * input MUX handling
433 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200434static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
435 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
438 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200439 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
440 if (mux_idx >= spec->num_mux_defs)
441 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100442 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
443 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200444 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200447static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
451 struct alc_spec *spec = codec->spec;
452 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
453
454 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
455 return 0;
456}
457
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200458static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
459 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
461 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
462 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100463 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100465 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100466 hda_nid_t nid = spec->capsrc_nids ?
467 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200468 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Takashi Iwaicd896c32008-11-18 12:36:33 +0100470 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
471 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100472 if (!imux->num_items && mux_idx > 0)
473 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100474
Takashi Iwaia22d5432009-07-27 12:54:26 +0200475 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200476 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100477 /* Matrix-mixer style (e.g. ALC882) */
478 unsigned int *cur_val = &spec->cur_mux[adc_idx];
479 unsigned int i, idx;
480
481 idx = ucontrol->value.enumerated.item[0];
482 if (idx >= imux->num_items)
483 idx = imux->num_items - 1;
484 if (*cur_val == idx)
485 return 0;
486 for (i = 0; i < imux->num_items; i++) {
487 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
488 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
489 imux->items[i].index,
490 HDA_AMP_MUTE, v);
491 }
492 *cur_val = idx;
493 return 1;
494 } else {
495 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100496 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100497 &spec->cur_mux[adc_idx]);
498 }
499}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
502 * channel mode setting
503 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200504static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
505 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
508 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100509 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
510 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200513static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
514 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
517 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100518 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200519 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200520 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200523static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
524 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
526 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
527 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200528 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
529 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200530 &spec->ext_channel_count);
531 if (err >= 0 && !spec->const_channel_count) {
532 spec->multiout.max_channels = spec->ext_channel_count;
533 if (spec->need_dac_fix)
534 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
535 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200536 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537}
538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100540 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200541 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100542 * being part of a format specifier. Maximum allowed length of a value is
543 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100544 *
545 * Note: some retasking pin complexes seem to ignore requests for input
546 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
547 * are requested. Therefore order this list so that this behaviour will not
548 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200549 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
550 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200551 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100552static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100553 "Mic 50pc bias", "Mic 80pc bias",
554 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100555};
556static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100557 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100558};
559/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200560 * in the pin being assumed to be exclusively an input or an output pin. In
561 * addition, "input" pins may or may not process the mic bias option
562 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
563 * accept requests for bias as of chip versions up to March 2006) and/or
564 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100565 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200566#define ALC_PIN_DIR_IN 0x00
567#define ALC_PIN_DIR_OUT 0x01
568#define ALC_PIN_DIR_INOUT 0x02
569#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
570#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100571
Kailang Yangea1fb292008-08-26 12:58:38 +0200572/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100573 * For each direction the minimum and maximum values are given.
574 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200575static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100576 { 0, 2 }, /* ALC_PIN_DIR_IN */
577 { 3, 4 }, /* ALC_PIN_DIR_OUT */
578 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200579 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
580 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100581};
582#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
583#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
584#define alc_pin_mode_n_items(_dir) \
585 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
586
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200587static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
588 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200589{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100590 unsigned int item_num = uinfo->value.enumerated.item;
591 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
592
593 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200594 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100595 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
596
597 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
598 item_num = alc_pin_mode_min(dir);
599 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200600 return 0;
601}
602
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200603static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
604 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200605{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100606 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200607 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
608 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100609 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200610 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200611 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
612 AC_VERB_GET_PIN_WIDGET_CONTROL,
613 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200614
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100615 /* Find enumerated value for current pinctl setting */
616 i = alc_pin_mode_min(dir);
Roel 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 Iwai840b64c2010-07-13 22:49:01 +02005169/* set the default connection to that pin */
5170static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5171{
5172 struct alc_spec *spec = codec->spec;
5173 int i;
5174
5175 for (i = 0; i < spec->num_adc_nids; i++) {
5176 hda_nid_t cap = spec->capsrc_nids ?
5177 spec->capsrc_nids[i] : spec->adc_nids[i];
5178 int idx;
5179
5180 idx = get_connection_index(codec, cap, pin);
5181 if (idx < 0)
5182 continue;
5183 /* select or unmute this route */
5184 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5185 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5186 HDA_AMP_MUTE, 0);
5187 } else {
5188 snd_hda_codec_write_cache(codec, cap, 0,
5189 AC_VERB_SET_CONNECT_SEL, idx);
5190 }
5191 return i; /* return the found index */
5192 }
5193 return -1; /* not found */
5194}
5195
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005196/* choose the ADC/MUX containing the input pin and initialize the setup */
5197static void fixup_single_adc(struct hda_codec *codec)
5198{
5199 struct alc_spec *spec = codec->spec;
Frederik Deweerdtd2db09b2010-03-05 16:34:31 +01005200 hda_nid_t pin = 0;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005201 int i;
5202
5203 /* search for the input pin; there must be only one */
5204 for (i = 0; i < AUTO_PIN_LAST; i++) {
5205 if (spec->autocfg.input_pins[i]) {
5206 pin = spec->autocfg.input_pins[i];
5207 break;
5208 }
5209 }
5210 if (!pin)
5211 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005212 i = init_capsrc_for_pin(codec, pin);
5213 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005214 /* use only this ADC */
5215 if (spec->capsrc_nids)
5216 spec->capsrc_nids += i;
5217 spec->adc_nids += i;
5218 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005219 }
5220}
5221
Takashi Iwai840b64c2010-07-13 22:49:01 +02005222/* initialize dual adcs */
5223static void fixup_dual_adc_switch(struct hda_codec *codec)
5224{
5225 struct alc_spec *spec = codec->spec;
5226 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5227 init_capsrc_for_pin(codec, spec->int_mic.pin);
5228}
5229
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005230static void set_capture_mixer(struct hda_codec *codec)
5231{
5232 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005233 static struct snd_kcontrol_new *caps[2][3] = {
5234 { alc_capture_mixer_nosrc1,
5235 alc_capture_mixer_nosrc2,
5236 alc_capture_mixer_nosrc3 },
5237 { alc_capture_mixer1,
5238 alc_capture_mixer2,
5239 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005240 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005241 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005242 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005243 int num_adcs = spec->num_adc_nids;
5244 if (spec->dual_adc_switch)
5245 fixup_dual_adc_switch(codec);
5246 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005247 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005248 else if (spec->input_mux) {
5249 if (spec->input_mux->num_items > 1)
5250 mux = 1;
5251 else if (spec->input_mux->num_items == 1)
5252 fixup_single_adc(codec);
5253 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005254 if (spec->dual_adc_switch)
5255 num_adcs = 1;
5256 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005257 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005258}
5259
Takashi Iwai66946352010-03-29 17:21:45 +02005260/* fill adc_nids (and capsrc_nids) containing all active input pins */
5261static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5262 int num_nids)
5263{
5264 struct alc_spec *spec = codec->spec;
5265 int n;
5266 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5267
5268 for (n = 0; n < num_nids; n++) {
5269 hda_nid_t adc, cap;
5270 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5271 int nconns, i, j;
5272
5273 adc = nids[n];
5274 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5275 continue;
5276 cap = adc;
5277 nconns = snd_hda_get_connections(codec, cap, conn,
5278 ARRAY_SIZE(conn));
5279 if (nconns == 1) {
5280 cap = conn[0];
5281 nconns = snd_hda_get_connections(codec, cap, conn,
5282 ARRAY_SIZE(conn));
5283 }
5284 if (nconns <= 0)
5285 continue;
5286 if (!fallback_adc) {
5287 fallback_adc = adc;
5288 fallback_cap = cap;
5289 }
5290 for (i = 0; i < AUTO_PIN_LAST; i++) {
5291 hda_nid_t nid = spec->autocfg.input_pins[i];
5292 if (!nid)
5293 continue;
5294 for (j = 0; j < nconns; j++) {
5295 if (conn[j] == nid)
5296 break;
5297 }
5298 if (j >= nconns)
5299 break;
5300 }
5301 if (i >= AUTO_PIN_LAST) {
5302 int num_adcs = spec->num_adc_nids;
5303 spec->private_adc_nids[num_adcs] = adc;
5304 spec->private_capsrc_nids[num_adcs] = cap;
5305 spec->num_adc_nids++;
5306 spec->adc_nids = spec->private_adc_nids;
5307 if (adc != cap)
5308 spec->capsrc_nids = spec->private_capsrc_nids;
5309 }
5310 }
5311 if (!spec->num_adc_nids) {
5312 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005313 " using fallback 0x%x\n",
5314 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005315 spec->private_adc_nids[0] = fallback_adc;
5316 spec->adc_nids = spec->private_adc_nids;
5317 if (fallback_adc != fallback_cap) {
5318 spec->private_capsrc_nids[0] = fallback_cap;
5319 spec->capsrc_nids = spec->private_adc_nids;
5320 }
5321 }
5322}
5323
Takashi Iwai67d634c2009-11-16 15:35:59 +01005324#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005325#define set_beep_amp(spec, nid, idx, dir) \
5326 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005327
5328static struct snd_pci_quirk beep_white_list[] = {
5329 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005330 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005331 {}
5332};
5333
5334static inline int has_cdefine_beep(struct hda_codec *codec)
5335{
5336 struct alc_spec *spec = codec->spec;
5337 const struct snd_pci_quirk *q;
5338 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5339 if (q)
5340 return q->value;
5341 return spec->cdefine.enable_pcbeep;
5342}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005343#else
5344#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005345#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005346#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005347
5348/*
5349 * OK, here we have finally the patch for ALC880
5350 */
5351
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352static int patch_alc880(struct hda_codec *codec)
5353{
5354 struct alc_spec *spec;
5355 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005356 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005358 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 if (spec == NULL)
5360 return -ENOMEM;
5361
5362 codec->spec = spec;
5363
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005364 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5365 alc880_models,
5366 alc880_cfg_tbl);
5367 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005368 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5369 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005370 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 }
5372
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005373 if (board_config == ALC880_AUTO) {
5374 /* automatic parse from the BIOS config */
5375 err = alc880_parse_auto_config(codec);
5376 if (err < 0) {
5377 alc_free(codec);
5378 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005379 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005380 printk(KERN_INFO
5381 "hda_codec: Cannot set up configuration "
5382 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005383 board_config = ALC880_3ST;
5384 }
5385 }
5386
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005387 err = snd_hda_attach_beep_device(codec, 0x1);
5388 if (err < 0) {
5389 alc_free(codec);
5390 return err;
5391 }
5392
Kailang Yangdf694da2005-12-05 19:42:22 +01005393 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005394 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5397 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005398 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5401 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5402
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005403 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005404 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005405 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005406 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005407 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005408 if (wcap != AC_WID_AUD_IN) {
5409 spec->adc_nids = alc880_adc_nids_alt;
5410 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005411 } else {
5412 spec->adc_nids = alc880_adc_nids;
5413 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005414 }
5415 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005416 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005417 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
Takashi Iwai2134ea42008-01-10 16:53:55 +01005419 spec->vmaster_nid = 0x0c;
5420
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005422 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005423 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005424#ifdef CONFIG_SND_HDA_POWER_SAVE
5425 if (!spec->loopback.amplist)
5426 spec->loopback.amplist = alc880_loopbacks;
5427#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428
5429 return 0;
5430}
5431
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005432
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433/*
5434 * ALC260 support
5435 */
5436
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005437static hda_nid_t alc260_dac_nids[1] = {
5438 /* front */
5439 0x02,
5440};
5441
5442static hda_nid_t alc260_adc_nids[1] = {
5443 /* ADC0 */
5444 0x04,
5445};
5446
Kailang Yangdf694da2005-12-05 19:42:22 +01005447static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005448 /* ADC1 */
5449 0x05,
5450};
5451
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005452/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5453 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5454 */
5455static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005456 /* ADC0, ADC1 */
5457 0x04, 0x05
5458};
5459
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005460#define ALC260_DIGOUT_NID 0x03
5461#define ALC260_DIGIN_NID 0x06
5462
5463static struct hda_input_mux alc260_capture_source = {
5464 .num_items = 4,
5465 .items = {
5466 { "Mic", 0x0 },
5467 { "Front Mic", 0x1 },
5468 { "Line", 0x2 },
5469 { "CD", 0x4 },
5470 },
5471};
5472
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005473/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005474 * headphone jack and the internal CD lines since these are the only pins at
5475 * which audio can appear. For flexibility, also allow the option of
5476 * recording the mixer output on the second ADC (ADC0 doesn't have a
5477 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005478 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005479static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5480 {
5481 .num_items = 3,
5482 .items = {
5483 { "Mic/Line", 0x0 },
5484 { "CD", 0x4 },
5485 { "Headphone", 0x2 },
5486 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005487 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005488 {
5489 .num_items = 4,
5490 .items = {
5491 { "Mic/Line", 0x0 },
5492 { "CD", 0x4 },
5493 { "Headphone", 0x2 },
5494 { "Mixer", 0x5 },
5495 },
5496 },
5497
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005498};
5499
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005500/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5501 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005502 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005503static struct hda_input_mux alc260_acer_capture_sources[2] = {
5504 {
5505 .num_items = 4,
5506 .items = {
5507 { "Mic", 0x0 },
5508 { "Line", 0x2 },
5509 { "CD", 0x4 },
5510 { "Headphone", 0x5 },
5511 },
5512 },
5513 {
5514 .num_items = 5,
5515 .items = {
5516 { "Mic", 0x0 },
5517 { "Line", 0x2 },
5518 { "CD", 0x4 },
5519 { "Headphone", 0x6 },
5520 { "Mixer", 0x5 },
5521 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005522 },
5523};
Michael Schwingencc959482009-02-22 18:58:45 +01005524
5525/* Maxdata Favorit 100XS */
5526static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5527 {
5528 .num_items = 2,
5529 .items = {
5530 { "Line/Mic", 0x0 },
5531 { "CD", 0x4 },
5532 },
5533 },
5534 {
5535 .num_items = 3,
5536 .items = {
5537 { "Line/Mic", 0x0 },
5538 { "CD", 0x4 },
5539 { "Mixer", 0x5 },
5540 },
5541 },
5542};
5543
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544/*
5545 * This is just place-holder, so there's something for alc_build_pcms to look
5546 * at when it calculates the maximum number of channels. ALC260 has no mixer
5547 * element which allows changing the channel mode, so the verb list is
5548 * never used.
5549 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005550static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 { 2, NULL },
5552};
5553
Kailang Yangdf694da2005-12-05 19:42:22 +01005554
5555/* Mixer combinations
5556 *
5557 * basic: base_output + input + pc_beep + capture
5558 * HP: base_output + input + capture_alt
5559 * HP_3013: hp_3013 + input + capture
5560 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005561 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005562 */
5563
5564static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005565 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005566 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005567 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5568 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5569 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5570 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5571 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005572};
Kailang Yangdf694da2005-12-05 19:42:22 +01005573
5574static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5576 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5577 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5578 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5579 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5580 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5581 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5582 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 { } /* end */
5584};
5585
Takashi Iwaibec15c32008-01-28 18:16:30 +01005586/* update HP, line and mono out pins according to the master switch */
5587static void alc260_hp_master_update(struct hda_codec *codec,
5588 hda_nid_t hp, hda_nid_t line,
5589 hda_nid_t mono)
5590{
5591 struct alc_spec *spec = codec->spec;
5592 unsigned int val = spec->master_sw ? PIN_HP : 0;
5593 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005594 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005595 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005596 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005597 val);
5598 /* mono (speaker) depending on the HP jack sense */
5599 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005600 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005601 val);
5602}
5603
5604static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5605 struct snd_ctl_elem_value *ucontrol)
5606{
5607 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5608 struct alc_spec *spec = codec->spec;
5609 *ucontrol->value.integer.value = spec->master_sw;
5610 return 0;
5611}
5612
5613static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5614 struct snd_ctl_elem_value *ucontrol)
5615{
5616 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5617 struct alc_spec *spec = codec->spec;
5618 int val = !!*ucontrol->value.integer.value;
5619 hda_nid_t hp, line, mono;
5620
5621 if (val == spec->master_sw)
5622 return 0;
5623 spec->master_sw = val;
5624 hp = (kcontrol->private_value >> 16) & 0xff;
5625 line = (kcontrol->private_value >> 8) & 0xff;
5626 mono = kcontrol->private_value & 0xff;
5627 alc260_hp_master_update(codec, hp, line, mono);
5628 return 1;
5629}
5630
5631static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5632 {
5633 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5634 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005635 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005636 .info = snd_ctl_boolean_mono_info,
5637 .get = alc260_hp_master_sw_get,
5638 .put = alc260_hp_master_sw_put,
5639 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5640 },
5641 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5642 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5643 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5644 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5645 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5646 HDA_OUTPUT),
5647 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5648 { } /* end */
5649};
5650
5651static struct hda_verb alc260_hp_unsol_verbs[] = {
5652 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5653 {},
5654};
5655
5656static void alc260_hp_automute(struct hda_codec *codec)
5657{
5658 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005659
Wu Fengguang864f92b2009-11-18 12:38:02 +08005660 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005661 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5662}
5663
5664static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5665{
5666 if ((res >> 26) == ALC880_HP_EVENT)
5667 alc260_hp_automute(codec);
5668}
5669
Kailang Yangdf694da2005-12-05 19:42:22 +01005670static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005671 {
5672 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5673 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005674 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005675 .info = snd_ctl_boolean_mono_info,
5676 .get = alc260_hp_master_sw_get,
5677 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005678 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005679 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005680 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5681 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5682 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5683 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5684 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5685 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005686 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5687 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005688 { } /* end */
5689};
5690
Kailang Yang3f878302008-08-26 13:02:23 +02005691static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5692 .ops = &snd_hda_bind_vol,
5693 .values = {
5694 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5695 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5696 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5697 0
5698 },
5699};
5700
5701static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5702 .ops = &snd_hda_bind_sw,
5703 .values = {
5704 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5705 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5706 0
5707 },
5708};
5709
5710static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5711 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5712 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5713 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5714 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5715 { } /* end */
5716};
5717
Takashi Iwaibec15c32008-01-28 18:16:30 +01005718static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5719 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5720 {},
5721};
5722
5723static void alc260_hp_3013_automute(struct hda_codec *codec)
5724{
5725 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005726
Wu Fengguang864f92b2009-11-18 12:38:02 +08005727 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005728 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005729}
5730
5731static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5732 unsigned int res)
5733{
5734 if ((res >> 26) == ALC880_HP_EVENT)
5735 alc260_hp_3013_automute(codec);
5736}
5737
Kailang Yang3f878302008-08-26 13:02:23 +02005738static void alc260_hp_3012_automute(struct hda_codec *codec)
5739{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005740 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005741
Kailang Yang3f878302008-08-26 13:02:23 +02005742 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5743 bits);
5744 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5745 bits);
5746 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5747 bits);
5748}
5749
5750static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5751 unsigned int res)
5752{
5753 if ((res >> 26) == ALC880_HP_EVENT)
5754 alc260_hp_3012_automute(codec);
5755}
5756
5757/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005758 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5759 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005760static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005761 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005762 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005763 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005764 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5765 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5766 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5767 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005768 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005769 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5770 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005771 { } /* end */
5772};
5773
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005774/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5775 * versions of the ALC260 don't act on requests to enable mic bias from NID
5776 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5777 * datasheet doesn't mention this restriction. At this stage it's not clear
5778 * whether this behaviour is intentional or is a hardware bug in chip
5779 * revisions available in early 2006. Therefore for now allow the
5780 * "Headphone Jack Mode" control to span all choices, but if it turns out
5781 * that the lack of mic bias for this NID is intentional we could change the
5782 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5783 *
5784 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5785 * don't appear to make the mic bias available from the "line" jack, even
5786 * though the NID used for this jack (0x14) can supply it. The theory is
5787 * that perhaps Acer have included blocking capacitors between the ALC260
5788 * and the output jack. If this turns out to be the case for all such
5789 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5790 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005791 *
5792 * The C20x Tablet series have a mono internal speaker which is controlled
5793 * via the chip's Mono sum widget and pin complex, so include the necessary
5794 * controls for such models. On models without a "mono speaker" the control
5795 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005796 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005797static struct snd_kcontrol_new alc260_acer_mixer[] = {
5798 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5799 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005800 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005801 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005802 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005803 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005804 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005805 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5806 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5807 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5808 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5809 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5810 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5811 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5812 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005813 { } /* end */
5814};
5815
Michael Schwingencc959482009-02-22 18:58:45 +01005816/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5817 */
5818static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5819 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5820 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5821 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5822 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5823 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5824 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5825 { } /* end */
5826};
5827
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005828/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5829 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5830 */
5831static struct snd_kcontrol_new alc260_will_mixer[] = {
5832 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5833 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5834 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5835 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5836 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5837 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5838 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5839 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5840 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5841 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005842 { } /* end */
5843};
5844
5845/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5846 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5847 */
5848static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5849 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5850 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5851 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5852 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5853 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5854 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5855 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5856 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5857 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5858 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5859 { } /* end */
5860};
5861
Kailang Yangdf694da2005-12-05 19:42:22 +01005862/*
5863 * initialization verbs
5864 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865static struct hda_verb alc260_init_verbs[] = {
5866 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005867 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005869 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005871 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005873 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005875 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005877 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005879 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005881 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005883 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5884 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005885 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 /* set connection select to line in (default select for this ADC) */
5887 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005888 /* mute capture amp left and right */
5889 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5890 /* set connection select to line in (default select for this ADC) */
5891 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005892 /* set vol=0 Line-Out mixer amp left and right */
5893 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5894 /* unmute pin widget amp left and right (no gain on this amp) */
5895 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5896 /* set vol=0 HP mixer amp left and right */
5897 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5898 /* unmute pin widget amp left and right (no gain on this amp) */
5899 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5900 /* set vol=0 Mono mixer amp left and right */
5901 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5902 /* unmute pin widget amp left and right (no gain on this amp) */
5903 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5904 /* unmute LINE-2 out pin */
5905 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005906 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5907 * Line In 2 = 0x03
5908 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005909 /* mute analog inputs */
5910 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5911 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5912 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5913 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5914 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005916 /* mute Front out path */
5917 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5918 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5919 /* mute Headphone out path */
5920 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5921 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5922 /* mute Mono out path */
5923 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5924 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 { }
5926};
5927
Takashi Iwai474167d2006-05-17 17:17:43 +02005928#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005929static struct hda_verb alc260_hp_init_verbs[] = {
5930 /* Headphone and output */
5931 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5932 /* mono output */
5933 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5934 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5935 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5936 /* Mic2 (front panel) pin widget for input and vref at 80% */
5937 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5938 /* Line In pin widget for input */
5939 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5940 /* Line-2 pin widget for output */
5941 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5942 /* CD pin widget for input */
5943 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5944 /* unmute amp left and right */
5945 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5946 /* set connection select to line in (default select for this ADC) */
5947 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5948 /* unmute Line-Out mixer amp left and right (volume = 0) */
5949 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5950 /* mute pin widget amp left and right (no gain on this amp) */
5951 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5952 /* unmute HP mixer amp left and right (volume = 0) */
5953 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5954 /* mute pin widget amp left and right (no gain on this amp) */
5955 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005956 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5957 * Line In 2 = 0x03
5958 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005959 /* mute analog inputs */
5960 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5961 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5962 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5963 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5964 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005965 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5966 /* Unmute Front out path */
5967 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5968 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5969 /* Unmute Headphone out path */
5970 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5971 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5972 /* Unmute Mono out path */
5973 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5974 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5975 { }
5976};
Takashi Iwai474167d2006-05-17 17:17:43 +02005977#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005978
5979static struct hda_verb alc260_hp_3013_init_verbs[] = {
5980 /* Line out and output */
5981 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5982 /* mono output */
5983 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5984 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5985 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5986 /* Mic2 (front panel) pin widget for input and vref at 80% */
5987 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5988 /* Line In pin widget for input */
5989 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5990 /* Headphone pin widget for output */
5991 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5992 /* CD pin widget for input */
5993 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5994 /* unmute amp left and right */
5995 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5996 /* set connection select to line in (default select for this ADC) */
5997 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5998 /* unmute Line-Out mixer amp left and right (volume = 0) */
5999 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6000 /* mute pin widget amp left and right (no gain on this amp) */
6001 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6002 /* unmute HP mixer amp left and right (volume = 0) */
6003 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6004 /* mute pin widget amp left and right (no gain on this amp) */
6005 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006006 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6007 * Line In 2 = 0x03
6008 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006009 /* mute analog inputs */
6010 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6011 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6012 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6013 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6014 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006015 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6016 /* Unmute Front out path */
6017 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6018 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6019 /* Unmute Headphone out path */
6020 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6021 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6022 /* Unmute Mono out path */
6023 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6024 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6025 { }
6026};
6027
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006028/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006029 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6030 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006031 */
6032static struct hda_verb alc260_fujitsu_init_verbs[] = {
6033 /* Disable all GPIOs */
6034 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6035 /* Internal speaker is connected to headphone pin */
6036 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6037 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6038 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006039 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6040 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6041 /* Ensure all other unused pins are disabled and muted. */
6042 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6043 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006044 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006045 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006046 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006047 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6048 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6049 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006050
Jonathan Woithef7ace402006-02-28 11:46:14 +01006051 /* Disable digital (SPDIF) pins */
6052 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6053 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006054
Kailang Yangea1fb292008-08-26 12:58:38 +02006055 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006056 * when acting as an output.
6057 */
6058 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6059
6060 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006061 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6062 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6063 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6064 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6065 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6066 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6067 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6068 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6069 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006070
Jonathan Woithef7ace402006-02-28 11:46:14 +01006071 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6072 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6073 /* Unmute Line1 pin widget output buffer since it starts as an output.
6074 * If the pin mode is changed by the user the pin mode control will
6075 * take care of enabling the pin's input/output buffers as needed.
6076 * Therefore there's no need to enable the input buffer at this
6077 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006078 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006079 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006080 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006081 * mixer ctrl)
6082 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006083 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006084
Jonathan Woithef7ace402006-02-28 11:46:14 +01006085 /* Mute capture amp left and right */
6086 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006087 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006088 * in (on mic1 pin)
6089 */
6090 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006091
Jonathan Woithef7ace402006-02-28 11:46:14 +01006092 /* Do the same for the second ADC: mute capture input amp and
6093 * set ADC connection to line in (on mic1 pin)
6094 */
6095 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6096 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006097
Jonathan Woithef7ace402006-02-28 11:46:14 +01006098 /* Mute all inputs to mixer widget (even unconnected ones) */
6099 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6100 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6101 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6102 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6103 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6104 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6105 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6106 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006107
6108 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006109};
6110
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006111/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6112 * similar laptops (adapted from Fujitsu init verbs).
6113 */
6114static struct hda_verb alc260_acer_init_verbs[] = {
6115 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6116 * the headphone jack. Turn this on and rely on the standard mute
6117 * methods whenever the user wants to turn these outputs off.
6118 */
6119 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6120 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6121 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6122 /* Internal speaker/Headphone jack is connected to Line-out pin */
6123 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6124 /* Internal microphone/Mic jack is connected to Mic1 pin */
6125 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6126 /* Line In jack is connected to Line1 pin */
6127 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006128 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6129 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006130 /* Ensure all other unused pins are disabled and muted. */
6131 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6132 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006133 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6134 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6135 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6136 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6137 /* Disable digital (SPDIF) pins */
6138 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6139 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6140
Kailang Yangea1fb292008-08-26 12:58:38 +02006141 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006142 * bus when acting as outputs.
6143 */
6144 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6145 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6146
6147 /* Start with output sum widgets muted and their output gains at min */
6148 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6149 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6150 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6151 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6152 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6153 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6154 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6155 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6156 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6157
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006158 /* Unmute Line-out pin widget amp left and right
6159 * (no equiv mixer ctrl)
6160 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006161 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006162 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6163 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006164 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6165 * inputs. If the pin mode is changed by the user the pin mode control
6166 * will take care of enabling the pin's input/output buffers as needed.
6167 * Therefore there's no need to enable the input buffer at this
6168 * stage.
6169 */
6170 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6171 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6172
6173 /* Mute capture amp left and right */
6174 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6175 /* Set ADC connection select to match default mixer setting - mic
6176 * (on mic1 pin)
6177 */
6178 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6179
6180 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006181 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006182 */
6183 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006184 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006185
6186 /* Mute all inputs to mixer widget (even unconnected ones) */
6187 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6188 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6189 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6190 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6191 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6192 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6193 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6194 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6195
6196 { }
6197};
6198
Michael Schwingencc959482009-02-22 18:58:45 +01006199/* Initialisation sequence for Maxdata Favorit 100XS
6200 * (adapted from Acer init verbs).
6201 */
6202static struct hda_verb alc260_favorit100_init_verbs[] = {
6203 /* GPIO 0 enables the output jack.
6204 * Turn this on and rely on the standard mute
6205 * methods whenever the user wants to turn these outputs off.
6206 */
6207 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6208 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6209 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6210 /* Line/Mic input jack is connected to Mic1 pin */
6211 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6212 /* Ensure all other unused pins are disabled and muted. */
6213 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6214 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6215 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6216 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6217 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6218 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6219 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6220 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6221 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6222 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6223 /* Disable digital (SPDIF) pins */
6224 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6225 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6226
6227 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6228 * bus when acting as outputs.
6229 */
6230 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6231 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6232
6233 /* Start with output sum widgets muted and their output gains at min */
6234 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6235 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6236 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6237 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6238 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6239 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6240 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6241 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6242 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6243
6244 /* Unmute Line-out pin widget amp left and right
6245 * (no equiv mixer ctrl)
6246 */
6247 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6248 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6249 * inputs. If the pin mode is changed by the user the pin mode control
6250 * will take care of enabling the pin's input/output buffers as needed.
6251 * Therefore there's no need to enable the input buffer at this
6252 * stage.
6253 */
6254 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6255
6256 /* Mute capture amp left and right */
6257 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6258 /* Set ADC connection select to match default mixer setting - mic
6259 * (on mic1 pin)
6260 */
6261 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6262
6263 /* Do similar with the second ADC: mute capture input amp and
6264 * set ADC connection to mic to match ALSA's default state.
6265 */
6266 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6267 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6268
6269 /* Mute all inputs to mixer widget (even unconnected ones) */
6270 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6271 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6275 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6278
6279 { }
6280};
6281
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006282static struct hda_verb alc260_will_verbs[] = {
6283 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6284 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6285 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6286 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6287 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6288 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6289 {}
6290};
6291
6292static struct hda_verb alc260_replacer_672v_verbs[] = {
6293 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6294 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6295 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6296
6297 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6298 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6299 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6300
6301 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6302 {}
6303};
6304
6305/* toggle speaker-output according to the hp-jack state */
6306static void alc260_replacer_672v_automute(struct hda_codec *codec)
6307{
6308 unsigned int present;
6309
6310 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006311 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006312 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006313 snd_hda_codec_write_cache(codec, 0x01, 0,
6314 AC_VERB_SET_GPIO_DATA, 1);
6315 snd_hda_codec_write_cache(codec, 0x0f, 0,
6316 AC_VERB_SET_PIN_WIDGET_CONTROL,
6317 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006318 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006319 snd_hda_codec_write_cache(codec, 0x01, 0,
6320 AC_VERB_SET_GPIO_DATA, 0);
6321 snd_hda_codec_write_cache(codec, 0x0f, 0,
6322 AC_VERB_SET_PIN_WIDGET_CONTROL,
6323 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006324 }
6325}
6326
6327static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6328 unsigned int res)
6329{
6330 if ((res >> 26) == ALC880_HP_EVENT)
6331 alc260_replacer_672v_automute(codec);
6332}
6333
Kailang Yang3f878302008-08-26 13:02:23 +02006334static struct hda_verb alc260_hp_dc7600_verbs[] = {
6335 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6336 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6337 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6338 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6339 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6340 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6341 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6342 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6343 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6344 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6345 {}
6346};
6347
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006348/* Test configuration for debugging, modelled after the ALC880 test
6349 * configuration.
6350 */
6351#ifdef CONFIG_SND_DEBUG
6352static hda_nid_t alc260_test_dac_nids[1] = {
6353 0x02,
6354};
6355static hda_nid_t alc260_test_adc_nids[2] = {
6356 0x04, 0x05,
6357};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006358/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006359 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006360 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006361 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006362static struct hda_input_mux alc260_test_capture_sources[2] = {
6363 {
6364 .num_items = 7,
6365 .items = {
6366 { "MIC1 pin", 0x0 },
6367 { "MIC2 pin", 0x1 },
6368 { "LINE1 pin", 0x2 },
6369 { "LINE2 pin", 0x3 },
6370 { "CD pin", 0x4 },
6371 { "LINE-OUT pin", 0x5 },
6372 { "HP-OUT pin", 0x6 },
6373 },
6374 },
6375 {
6376 .num_items = 8,
6377 .items = {
6378 { "MIC1 pin", 0x0 },
6379 { "MIC2 pin", 0x1 },
6380 { "LINE1 pin", 0x2 },
6381 { "LINE2 pin", 0x3 },
6382 { "CD pin", 0x4 },
6383 { "Mixer", 0x5 },
6384 { "LINE-OUT pin", 0x6 },
6385 { "HP-OUT pin", 0x7 },
6386 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006387 },
6388};
6389static struct snd_kcontrol_new alc260_test_mixer[] = {
6390 /* Output driver widgets */
6391 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6392 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6393 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6394 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6395 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6396 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6397
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006398 /* Modes for retasking pin widgets
6399 * Note: the ALC260 doesn't seem to act on requests to enable mic
6400 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6401 * mention this restriction. At this stage it's not clear whether
6402 * this behaviour is intentional or is a hardware bug in chip
6403 * revisions available at least up until early 2006. Therefore for
6404 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6405 * choices, but if it turns out that the lack of mic bias for these
6406 * NIDs is intentional we could change their modes from
6407 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6408 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006409 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6410 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6411 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6412 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6413 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6414 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6415
6416 /* Loopback mixer controls */
6417 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6418 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6419 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6420 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6421 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6422 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6423 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6424 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6425 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6426 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006427 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6428 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6429 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6430 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006431
6432 /* Controls for GPIO pins, assuming they are configured as outputs */
6433 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6434 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6435 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6436 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6437
Jonathan Woithe92621f12006-02-28 11:47:47 +01006438 /* Switches to allow the digital IO pins to be enabled. The datasheet
6439 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006440 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006441 */
6442 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6443 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6444
Jonathan Woithef8225f62008-01-08 12:16:54 +01006445 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6446 * this output to turn on an external amplifier.
6447 */
6448 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6449 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6450
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006451 { } /* end */
6452};
6453static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006454 /* Enable all GPIOs as outputs with an initial value of 0 */
6455 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6456 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6457 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6458
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006459 /* Enable retasking pins as output, initially without power amp */
6460 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6461 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6462 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6463 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6464 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6465 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6466
Jonathan Woithe92621f12006-02-28 11:47:47 +01006467 /* Disable digital (SPDIF) pins initially, but users can enable
6468 * them via a mixer switch. In the case of SPDIF-out, this initverb
6469 * payload also sets the generation to 0, output to be in "consumer"
6470 * PCM format, copyright asserted, no pre-emphasis and no validity
6471 * control.
6472 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006473 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6474 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6475
Kailang Yangea1fb292008-08-26 12:58:38 +02006476 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006477 * OUT1 sum bus when acting as an output.
6478 */
6479 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6480 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6481 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6482 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6483
6484 /* Start with output sum widgets muted and their output gains at min */
6485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6486 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6487 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6488 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6489 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6490 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6491 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6492 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6493 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6494
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006495 /* Unmute retasking pin widget output buffers since the default
6496 * state appears to be output. As the pin mode is changed by the
6497 * user the pin mode control will take care of enabling the pin's
6498 * input/output buffers as needed.
6499 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006500 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6501 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6502 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6503 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6504 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6505 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6506 /* Also unmute the mono-out pin widget */
6507 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6508
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006509 /* Mute capture amp left and right */
6510 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006511 /* Set ADC connection select to match default mixer setting (mic1
6512 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006513 */
6514 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6515
6516 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006517 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006518 */
6519 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6520 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6521
6522 /* Mute all inputs to mixer widget (even unconnected ones) */
6523 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6524 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6525 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6526 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6527 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6530 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6531
6532 { }
6533};
6534#endif
6535
Takashi Iwai63300792008-01-24 15:31:36 +01006536#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6537#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006538
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006539#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6540#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6541
Kailang Yangdf694da2005-12-05 19:42:22 +01006542/*
6543 * for BIOS auto-configuration
6544 */
6545
6546static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006547 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006548{
6549 hda_nid_t nid_vol;
6550 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006551 int err;
6552
6553 if (nid >= 0x0f && nid < 0x11) {
6554 nid_vol = nid - 0x7;
6555 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6556 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6557 } else if (nid == 0x11) {
6558 nid_vol = nid - 0x7;
6559 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6560 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6561 } else if (nid >= 0x12 && nid <= 0x15) {
6562 nid_vol = 0x08;
6563 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6564 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6565 } else
6566 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006567
Takashi Iwai863b4512008-10-21 17:01:47 +02006568 if (!(*vol_bits & (1 << nid_vol))) {
6569 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006570 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006571 if (err < 0)
6572 return err;
6573 *vol_bits |= (1 << nid_vol);
6574 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006575 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006576 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006577 return err;
6578 return 1;
6579}
6580
6581/* add playback controls from the parsed DAC table */
6582static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6583 const struct auto_pin_cfg *cfg)
6584{
6585 hda_nid_t nid;
6586 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006587 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006588
6589 spec->multiout.num_dacs = 1;
6590 spec->multiout.dac_nids = spec->private_dac_nids;
6591 spec->multiout.dac_nids[0] = 0x02;
6592
6593 nid = cfg->line_out_pins[0];
6594 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006595 const char *pfx;
6596 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6597 pfx = "Master";
6598 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6599 pfx = "Speaker";
6600 else
6601 pfx = "Front";
6602 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006603 if (err < 0)
6604 return err;
6605 }
6606
Takashi Iwai82bc9552006-03-21 11:24:42 +01006607 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006608 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006609 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006610 if (err < 0)
6611 return err;
6612 }
6613
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006614 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006615 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006616 err = alc260_add_playback_controls(spec, nid, "Headphone",
6617 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006618 if (err < 0)
6619 return err;
6620 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006621 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006622}
6623
6624/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006625static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006626 const struct auto_pin_cfg *cfg)
6627{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006628 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006629}
6630
6631static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6632 hda_nid_t nid, int pin_type,
6633 int sel_idx)
6634{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006635 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006636 /* need the manual connection? */
6637 if (nid >= 0x12) {
6638 int idx = nid - 0x12;
6639 snd_hda_codec_write(codec, idx + 0x0b, 0,
6640 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006641 }
6642}
6643
6644static void alc260_auto_init_multi_out(struct hda_codec *codec)
6645{
6646 struct alc_spec *spec = codec->spec;
6647 hda_nid_t nid;
6648
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006649 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006650 if (nid) {
6651 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6652 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6653 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006654
Takashi Iwai82bc9552006-03-21 11:24:42 +01006655 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006656 if (nid)
6657 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6658
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006659 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006660 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006661 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006662}
Kailang Yangdf694da2005-12-05 19:42:22 +01006663
6664#define ALC260_PIN_CD_NID 0x16
6665static void alc260_auto_init_analog_input(struct hda_codec *codec)
6666{
6667 struct alc_spec *spec = codec->spec;
6668 int i;
6669
6670 for (i = 0; i < AUTO_PIN_LAST; i++) {
6671 hda_nid_t nid = spec->autocfg.input_pins[i];
6672 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006673 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006674 if (nid != ALC260_PIN_CD_NID &&
6675 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006676 snd_hda_codec_write(codec, nid, 0,
6677 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006678 AMP_OUT_MUTE);
6679 }
6680 }
6681}
6682
Takashi Iwai7f311a42010-04-09 17:32:23 +02006683#define alc260_auto_init_input_src alc880_auto_init_input_src
6684
Kailang Yangdf694da2005-12-05 19:42:22 +01006685/*
6686 * generic initialization of ADC, input mixers and output mixers
6687 */
6688static struct hda_verb alc260_volume_init_verbs[] = {
6689 /*
6690 * Unmute ADC0-1 and set the default input to mic-in
6691 */
6692 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6693 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6694 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6695 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006696
Kailang Yangdf694da2005-12-05 19:42:22 +01006697 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6698 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006699 * Note: PASD motherboards uses the Line In 2 as the input for
6700 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006701 */
6702 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006703 /* mute analog inputs */
6704 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6705 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6706 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6707 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6708 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006709
6710 /*
6711 * Set up output mixers (0x08 - 0x0a)
6712 */
6713 /* set vol=0 to output mixers */
6714 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6715 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6716 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6717 /* set up input amps for analog loopback */
6718 /* Amp Indices: DAC = 0, mixer = 1 */
6719 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6720 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6721 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6722 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6723 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6724 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006725
Kailang Yangdf694da2005-12-05 19:42:22 +01006726 { }
6727};
6728
6729static int alc260_parse_auto_config(struct hda_codec *codec)
6730{
6731 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006732 int err;
6733 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6734
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006735 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6736 alc260_ignore);
6737 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006738 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006739 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6740 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006741 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006742 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006743 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006744 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006745 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006746 return err;
6747
6748 spec->multiout.max_channels = 2;
6749
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006750 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006751 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006752 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006753 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006754
Takashi Iwaid88897e2008-10-31 15:01:37 +01006755 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006756
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006757 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006758 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006759
Kailang Yang6227cdc2010-02-25 08:36:52 +01006760 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006761
Kailang Yangdf694da2005-12-05 19:42:22 +01006762 return 1;
6763}
6764
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006765/* additional initialization for auto-configuration model */
6766static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006767{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006768 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006769 alc260_auto_init_multi_out(codec);
6770 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02006771 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02006772 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006773 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006774 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006775}
6776
Takashi Iwaicb53c622007-08-10 17:21:45 +02006777#ifdef CONFIG_SND_HDA_POWER_SAVE
6778static struct hda_amp_list alc260_loopbacks[] = {
6779 { 0x07, HDA_INPUT, 0 },
6780 { 0x07, HDA_INPUT, 1 },
6781 { 0x07, HDA_INPUT, 2 },
6782 { 0x07, HDA_INPUT, 3 },
6783 { 0x07, HDA_INPUT, 4 },
6784 { } /* end */
6785};
6786#endif
6787
Kailang Yangdf694da2005-12-05 19:42:22 +01006788/*
6789 * ALC260 configurations
6790 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006791static const char *alc260_models[ALC260_MODEL_LAST] = {
6792 [ALC260_BASIC] = "basic",
6793 [ALC260_HP] = "hp",
6794 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006795 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006796 [ALC260_FUJITSU_S702X] = "fujitsu",
6797 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006798 [ALC260_WILL] = "will",
6799 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006800 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006801#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006802 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006803#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006804 [ALC260_AUTO] = "auto",
6805};
6806
6807static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006808 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006809 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006810 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006811 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006812 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006813 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006814 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006815 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006816 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006817 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6818 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6819 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6820 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6821 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6822 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6823 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6824 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6825 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006826 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006827 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006828 {}
6829};
6830
Kailang Yangdf694da2005-12-05 19:42:22 +01006831static struct alc_config_preset alc260_presets[] = {
6832 [ALC260_BASIC] = {
6833 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006834 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006835 .init_verbs = { alc260_init_verbs },
6836 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6837 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006838 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01006839 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006840 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6841 .channel_mode = alc260_modes,
6842 .input_mux = &alc260_capture_source,
6843 },
6844 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006845 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006846 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006847 .init_verbs = { alc260_init_verbs,
6848 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006849 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6850 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006851 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6852 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006853 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6854 .channel_mode = alc260_modes,
6855 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006856 .unsol_event = alc260_hp_unsol_event,
6857 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006858 },
Kailang Yang3f878302008-08-26 13:02:23 +02006859 [ALC260_HP_DC7600] = {
6860 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006861 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006862 .init_verbs = { alc260_init_verbs,
6863 alc260_hp_dc7600_verbs },
6864 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6865 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006866 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6867 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006868 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6869 .channel_mode = alc260_modes,
6870 .input_mux = &alc260_capture_source,
6871 .unsol_event = alc260_hp_3012_unsol_event,
6872 .init_hook = alc260_hp_3012_automute,
6873 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006874 [ALC260_HP_3013] = {
6875 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006876 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006877 .init_verbs = { alc260_hp_3013_init_verbs,
6878 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006879 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6880 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006881 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6882 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006883 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6884 .channel_mode = alc260_modes,
6885 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006886 .unsol_event = alc260_hp_3013_unsol_event,
6887 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006888 },
6889 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006890 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006891 .init_verbs = { alc260_fujitsu_init_verbs },
6892 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6893 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006894 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6895 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006896 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6897 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006898 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6899 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006900 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006901 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006902 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006903 .init_verbs = { alc260_acer_init_verbs },
6904 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6905 .dac_nids = alc260_dac_nids,
6906 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6907 .adc_nids = alc260_dual_adc_nids,
6908 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6909 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006910 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6911 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006912 },
Michael Schwingencc959482009-02-22 18:58:45 +01006913 [ALC260_FAVORIT100] = {
6914 .mixers = { alc260_favorit100_mixer },
6915 .init_verbs = { alc260_favorit100_init_verbs },
6916 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6917 .dac_nids = alc260_dac_nids,
6918 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6919 .adc_nids = alc260_dual_adc_nids,
6920 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6921 .channel_mode = alc260_modes,
6922 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6923 .input_mux = alc260_favorit100_capture_sources,
6924 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006925 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006926 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006927 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6928 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6929 .dac_nids = alc260_dac_nids,
6930 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6931 .adc_nids = alc260_adc_nids,
6932 .dig_out_nid = ALC260_DIGOUT_NID,
6933 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6934 .channel_mode = alc260_modes,
6935 .input_mux = &alc260_capture_source,
6936 },
6937 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006938 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006939 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6940 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6941 .dac_nids = alc260_dac_nids,
6942 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6943 .adc_nids = alc260_adc_nids,
6944 .dig_out_nid = ALC260_DIGOUT_NID,
6945 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6946 .channel_mode = alc260_modes,
6947 .input_mux = &alc260_capture_source,
6948 .unsol_event = alc260_replacer_672v_unsol_event,
6949 .init_hook = alc260_replacer_672v_automute,
6950 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006951#ifdef CONFIG_SND_DEBUG
6952 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006953 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006954 .init_verbs = { alc260_test_init_verbs },
6955 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6956 .dac_nids = alc260_test_dac_nids,
6957 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6958 .adc_nids = alc260_test_adc_nids,
6959 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6960 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006961 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6962 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006963 },
6964#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006965};
6966
Linus Torvalds1da177e2005-04-16 15:20:36 -07006967static int patch_alc260(struct hda_codec *codec)
6968{
6969 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006970 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006971
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006972 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006973 if (spec == NULL)
6974 return -ENOMEM;
6975
6976 codec->spec = spec;
6977
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006978 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6979 alc260_models,
6980 alc260_cfg_tbl);
6981 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006982 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006983 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006984 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006985 }
6986
Kailang Yangdf694da2005-12-05 19:42:22 +01006987 if (board_config == ALC260_AUTO) {
6988 /* automatic parse from the BIOS config */
6989 err = alc260_parse_auto_config(codec);
6990 if (err < 0) {
6991 alc_free(codec);
6992 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006993 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006994 printk(KERN_INFO
6995 "hda_codec: Cannot set up configuration "
6996 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006997 board_config = ALC260_BASIC;
6998 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007001 err = snd_hda_attach_beep_device(codec, 0x1);
7002 if (err < 0) {
7003 alc_free(codec);
7004 return err;
7005 }
7006
Kailang Yangdf694da2005-12-05 19:42:22 +01007007 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007008 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009
Linus Torvalds1da177e2005-04-16 15:20:36 -07007010 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7011 spec->stream_analog_capture = &alc260_pcm_analog_capture;
7012
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007013 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7014 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7015
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007016 if (!spec->adc_nids && spec->input_mux) {
7017 /* check whether NID 0x04 is valid */
7018 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007019 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007020 /* get type */
7021 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7022 spec->adc_nids = alc260_adc_nids_alt;
7023 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7024 } else {
7025 spec->adc_nids = alc260_adc_nids;
7026 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7027 }
7028 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007029 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007030 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007031
Takashi Iwai2134ea42008-01-10 16:53:55 +01007032 spec->vmaster_nid = 0x08;
7033
Linus Torvalds1da177e2005-04-16 15:20:36 -07007034 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007035 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007036 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007037#ifdef CONFIG_SND_HDA_POWER_SAVE
7038 if (!spec->loopback.amplist)
7039 spec->loopback.amplist = alc260_loopbacks;
7040#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041
7042 return 0;
7043}
7044
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007045
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007047 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007048 *
7049 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7050 * configuration. Each pin widget can choose any input DACs and a mixer.
7051 * Each ADC is connected from a mixer of all inputs. This makes possible
7052 * 6-channel independent captures.
7053 *
7054 * In addition, an independent DAC for the multi-playback (not used in this
7055 * driver yet).
7056 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007057#define ALC882_DIGOUT_NID 0x06
7058#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02007059#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7060#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7061#define ALC1200_DIGOUT_NID 0x10
7062
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007064static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065 { 8, NULL }
7066};
7067
Takashi Iwai4953550a2009-06-30 15:28:30 +02007068/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069static hda_nid_t alc882_dac_nids[4] = {
7070 /* front, rear, clfe, rear_surr */
7071 0x02, 0x03, 0x04, 0x05
7072};
Takashi Iwai4953550a2009-06-30 15:28:30 +02007073#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007074
Takashi Iwai4953550a2009-06-30 15:28:30 +02007075/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007076#define alc882_adc_nids alc880_adc_nids
7077#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02007078#define alc883_adc_nids alc882_adc_nids_alt
7079static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7080static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7081#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082
Takashi Iwaie1406342008-02-11 18:32:32 +01007083static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7084static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007085#define alc883_capsrc_nids alc882_capsrc_nids_alt
7086static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7087#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007088
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089/* input MUX */
7090/* FIXME: should be a matrix-type input source selection */
7091
7092static struct hda_input_mux alc882_capture_source = {
7093 .num_items = 4,
7094 .items = {
7095 { "Mic", 0x0 },
7096 { "Front Mic", 0x1 },
7097 { "Line", 0x2 },
7098 { "CD", 0x4 },
7099 },
7100};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007101
Takashi Iwai4953550a2009-06-30 15:28:30 +02007102#define alc883_capture_source alc882_capture_source
7103
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007104static struct hda_input_mux alc889_capture_source = {
7105 .num_items = 3,
7106 .items = {
7107 { "Front Mic", 0x0 },
7108 { "Mic", 0x3 },
7109 { "Line", 0x2 },
7110 },
7111};
7112
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007113static struct hda_input_mux mb5_capture_source = {
7114 .num_items = 3,
7115 .items = {
7116 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307117 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007118 { "CD", 0x4 },
7119 },
7120};
7121
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007122static struct hda_input_mux macmini3_capture_source = {
7123 .num_items = 2,
7124 .items = {
7125 { "Line", 0x2 },
7126 { "CD", 0x4 },
7127 },
7128};
7129
Takashi Iwai4953550a2009-06-30 15:28:30 +02007130static struct hda_input_mux alc883_3stack_6ch_intel = {
7131 .num_items = 4,
7132 .items = {
7133 { "Mic", 0x1 },
7134 { "Front Mic", 0x0 },
7135 { "Line", 0x2 },
7136 { "CD", 0x4 },
7137 },
7138};
7139
7140static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7141 .num_items = 2,
7142 .items = {
7143 { "Mic", 0x1 },
7144 { "Line", 0x2 },
7145 },
7146};
7147
7148static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7149 .num_items = 4,
7150 .items = {
7151 { "Mic", 0x0 },
David Henningsson150b4322010-07-29 14:46:42 +02007152 { "Int Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007153 { "Line", 0x2 },
7154 { "CD", 0x4 },
7155 },
7156};
7157
7158static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7159 .num_items = 2,
7160 .items = {
7161 { "Mic", 0x0 },
7162 { "Int Mic", 0x1 },
7163 },
7164};
7165
7166static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7167 .num_items = 3,
7168 .items = {
7169 { "Mic", 0x0 },
7170 { "Front Mic", 0x1 },
7171 { "Line", 0x4 },
7172 },
7173};
7174
7175static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7176 .num_items = 2,
7177 .items = {
7178 { "Mic", 0x0 },
7179 { "Line", 0x2 },
7180 },
7181};
7182
7183static struct hda_input_mux alc889A_mb31_capture_source = {
7184 .num_items = 2,
7185 .items = {
7186 { "Mic", 0x0 },
7187 /* Front Mic (0x01) unused */
7188 { "Line", 0x2 },
7189 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007190 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007191 },
7192};
7193
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007194static struct hda_input_mux alc889A_imac91_capture_source = {
7195 .num_items = 2,
7196 .items = {
7197 { "Mic", 0x01 },
7198 { "Line", 0x2 }, /* Not sure! */
7199 },
7200};
7201
Takashi Iwai4953550a2009-06-30 15:28:30 +02007202/*
7203 * 2ch mode
7204 */
7205static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7206 { 2, NULL }
7207};
7208
Kailang Yangdf694da2005-12-05 19:42:22 +01007209/*
Kailang Yang272a5272007-05-14 11:00:38 +02007210 * 2ch mode
7211 */
7212static struct hda_verb alc882_3ST_ch2_init[] = {
7213 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7214 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7215 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7216 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7217 { } /* end */
7218};
7219
7220/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007221 * 4ch mode
7222 */
7223static struct hda_verb alc882_3ST_ch4_init[] = {
7224 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7225 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7226 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7227 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7228 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7229 { } /* end */
7230};
7231
7232/*
Kailang Yang272a5272007-05-14 11:00:38 +02007233 * 6ch mode
7234 */
7235static struct hda_verb alc882_3ST_ch6_init[] = {
7236 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7237 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7238 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7239 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7240 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7241 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7242 { } /* end */
7243};
7244
Takashi Iwai4953550a2009-06-30 15:28:30 +02007245static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007246 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007247 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007248 { 6, alc882_3ST_ch6_init },
7249};
7250
Takashi Iwai4953550a2009-06-30 15:28:30 +02007251#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7252
Kailang Yang272a5272007-05-14 11:00:38 +02007253/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307254 * 2ch mode
7255 */
7256static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7257 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7258 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7259 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7260 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7261 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7262 { } /* end */
7263};
7264
7265/*
7266 * 4ch mode
7267 */
7268static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7269 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7270 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7271 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7272 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7273 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7274 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7275 { } /* end */
7276};
7277
7278/*
7279 * 6ch mode
7280 */
7281static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7282 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7283 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7284 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7285 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7286 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7287 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7288 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7289 { } /* end */
7290};
7291
7292static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7293 { 2, alc883_3ST_ch2_clevo_init },
7294 { 4, alc883_3ST_ch4_clevo_init },
7295 { 6, alc883_3ST_ch6_clevo_init },
7296};
7297
7298
7299/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007300 * 6ch mode
7301 */
7302static struct hda_verb alc882_sixstack_ch6_init[] = {
7303 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7304 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7305 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7306 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7307 { } /* end */
7308};
7309
7310/*
7311 * 8ch mode
7312 */
7313static struct hda_verb alc882_sixstack_ch8_init[] = {
7314 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7315 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7316 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7317 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7318 { } /* end */
7319};
7320
7321static struct hda_channel_mode alc882_sixstack_modes[2] = {
7322 { 6, alc882_sixstack_ch6_init },
7323 { 8, alc882_sixstack_ch8_init },
7324};
7325
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007326
7327/* Macbook Air 2,1 */
7328
7329static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7330 { 2, NULL },
7331};
7332
Takashi Iwai87350ad2007-08-16 18:19:38 +02007333/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007334 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007335 */
7336
7337/*
7338 * 2ch mode
7339 */
7340static struct hda_verb alc885_mbp_ch2_init[] = {
7341 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7342 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7343 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7344 { } /* end */
7345};
7346
7347/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007348 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007349 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007350static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007351 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7352 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7353 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7354 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7355 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7356 { } /* end */
7357};
7358
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007359static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007360 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007361 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007362};
7363
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007364/*
7365 * 2ch
7366 * Speakers/Woofer/HP = Front
7367 * LineIn = Input
7368 */
7369static struct hda_verb alc885_mb5_ch2_init[] = {
7370 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7371 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7372 { } /* end */
7373};
7374
7375/*
7376 * 6ch mode
7377 * Speakers/HP = Front
7378 * Woofer = LFE
7379 * LineIn = Surround
7380 */
7381static struct hda_verb alc885_mb5_ch6_init[] = {
7382 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7383 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7384 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7385 { } /* end */
7386};
7387
7388static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7389 { 2, alc885_mb5_ch2_init },
7390 { 6, alc885_mb5_ch6_init },
7391};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007392
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007393#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai4953550a2009-06-30 15:28:30 +02007394
7395/*
7396 * 2ch mode
7397 */
7398static struct hda_verb alc883_4ST_ch2_init[] = {
7399 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7400 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7401 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7402 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7403 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7404 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7405 { } /* end */
7406};
7407
7408/*
7409 * 4ch mode
7410 */
7411static struct hda_verb alc883_4ST_ch4_init[] = {
7412 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7413 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7414 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7415 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7416 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7417 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7418 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7419 { } /* end */
7420};
7421
7422/*
7423 * 6ch mode
7424 */
7425static struct hda_verb alc883_4ST_ch6_init[] = {
7426 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7427 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7428 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7429 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7430 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7431 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7432 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7433 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7434 { } /* end */
7435};
7436
7437/*
7438 * 8ch mode
7439 */
7440static struct hda_verb alc883_4ST_ch8_init[] = {
7441 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7442 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7443 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7444 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7445 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7446 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7447 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7448 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7449 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7450 { } /* end */
7451};
7452
7453static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7454 { 2, alc883_4ST_ch2_init },
7455 { 4, alc883_4ST_ch4_init },
7456 { 6, alc883_4ST_ch6_init },
7457 { 8, alc883_4ST_ch8_init },
7458};
7459
7460
7461/*
7462 * 2ch mode
7463 */
7464static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7465 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7466 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7467 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7468 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7469 { } /* end */
7470};
7471
7472/*
7473 * 4ch mode
7474 */
7475static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7476 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7477 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7478 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7479 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7480 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7481 { } /* end */
7482};
7483
7484/*
7485 * 6ch mode
7486 */
7487static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7488 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7489 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7490 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7491 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7492 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7493 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7494 { } /* end */
7495};
7496
7497static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7498 { 2, alc883_3ST_ch2_intel_init },
7499 { 4, alc883_3ST_ch4_intel_init },
7500 { 6, alc883_3ST_ch6_intel_init },
7501};
7502
7503/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007504 * 2ch mode
7505 */
7506static struct hda_verb alc889_ch2_intel_init[] = {
7507 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7508 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7509 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7510 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7511 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7512 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7513 { } /* end */
7514};
7515
7516/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007517 * 6ch mode
7518 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007519static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007520 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7521 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7522 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7523 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7524 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007525 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7526 { } /* end */
7527};
7528
7529/*
7530 * 8ch mode
7531 */
7532static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007533 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7534 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7535 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7536 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7537 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007538 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7539 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007540 { } /* end */
7541};
7542
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007543static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7544 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007545 { 6, alc889_ch6_intel_init },
7546 { 8, alc889_ch8_intel_init },
7547};
7548
7549/*
7550 * 6ch mode
7551 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007552static struct hda_verb alc883_sixstack_ch6_init[] = {
7553 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7554 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7555 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7556 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7557 { } /* end */
7558};
7559
7560/*
7561 * 8ch mode
7562 */
7563static struct hda_verb alc883_sixstack_ch8_init[] = {
7564 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7565 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7566 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7567 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7568 { } /* end */
7569};
7570
7571static struct hda_channel_mode alc883_sixstack_modes[2] = {
7572 { 6, alc883_sixstack_ch6_init },
7573 { 8, alc883_sixstack_ch8_init },
7574};
7575
7576
Linus Torvalds1da177e2005-04-16 15:20:36 -07007577/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7578 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7579 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01007580static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007581 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007582 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007583 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007584 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007585 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7586 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007587 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7588 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007589 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007590 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7592 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7593 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7594 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7595 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7596 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007597 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007598 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7599 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007600 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007602 { } /* end */
7603};
7604
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007605/* Macbook Air 2,1 same control for HP and internal Speaker */
7606
7607static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7608 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7609 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7610 { }
7611};
7612
7613
Takashi Iwai87350ad2007-08-16 18:19:38 +02007614static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007615 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7616 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7617 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7618 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7619 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007620 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7621 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007622 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7623 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007624 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007625 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7626 { } /* end */
7627};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007628
7629static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007630 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7631 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7632 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7633 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7634 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7635 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307636 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7637 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307638 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7639 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007640 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7641 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7642 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7643 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7644 { } /* end */
7645};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007646
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007647static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7648 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7649 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7650 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7651 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7652 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7653 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7654 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7655 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7656 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7657 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
7658 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7659 { } /* end */
7660};
7661
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007662static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007663 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7664 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007665 { } /* end */
7666};
7667
7668
Kailang Yangbdd148a2007-05-08 15:19:08 +02007669static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7670 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7671 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7672 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7673 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7674 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7675 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7676 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7677 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7678 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007679 { } /* end */
7680};
7681
Kailang Yang272a5272007-05-14 11:00:38 +02007682static struct snd_kcontrol_new alc882_targa_mixer[] = {
7683 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7684 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7685 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7686 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7687 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7688 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7689 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7690 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7691 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007692 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007693 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7694 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007695 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007696 { } /* end */
7697};
7698
7699/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7700 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7701 */
7702static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7703 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7704 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7705 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7706 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7707 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7708 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7709 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7710 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7711 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7712 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7713 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7714 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02007715 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007716 { } /* end */
7717};
7718
Takashi Iwai914759b2007-09-06 14:52:04 +02007719static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7720 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7721 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7722 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7723 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7724 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7725 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7726 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7727 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7728 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7729 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007730 { } /* end */
7731};
7732
Kailang Yangdf694da2005-12-05 19:42:22 +01007733static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7734 {
7735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7736 .name = "Channel Mode",
7737 .info = alc_ch_mode_info,
7738 .get = alc_ch_mode_get,
7739 .put = alc_ch_mode_put,
7740 },
7741 { } /* end */
7742};
7743
Takashi Iwai4953550a2009-06-30 15:28:30 +02007744static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007745 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7747 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7750 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007752 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7753 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007755 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7756 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007757
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007758 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007759 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007760 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007762 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007763 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007764 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007765 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007766 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007767 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007768 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007769 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007770 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007771 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007772 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007773 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007774 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007775 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007776 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7777 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007778 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007779 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7780 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007781 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007782 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7783 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7784 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7785 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7786 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007787 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007788 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
7790 /* FIXME: use matrix-type input source selection */
7791 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007792 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007793 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007795 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007796 /* ADC2: mute amp left and right */
7797 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007798 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007799 /* ADC3: mute amp left and right */
7800 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007801 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007802
7803 { }
7804};
7805
Takashi Iwai4953550a2009-06-30 15:28:30 +02007806static struct hda_verb alc882_adc1_init_verbs[] = {
7807 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7808 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7809 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7810 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7811 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7812 /* ADC1: mute amp left and right */
7813 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7814 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7815 { }
7816};
7817
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007818static struct hda_verb alc882_eapd_verbs[] = {
7819 /* change to EAPD mode */
7820 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007821 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007822 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007823};
7824
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007825static struct hda_verb alc889_eapd_verbs[] = {
7826 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7827 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7828 { }
7829};
7830
Wu Fengguang6732bd02009-07-30 09:19:14 +02007831static struct hda_verb alc_hp15_unsol_verbs[] = {
7832 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7833 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7834 {}
7835};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007836
7837static struct hda_verb alc885_init_verbs[] = {
7838 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01007839 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7840 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007841 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007842 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7843 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007844 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007845 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7846 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007847 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01007848 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7849 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007850
7851 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007852 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007853 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7854 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7855 /* Front Pin: output 0 (0x0c) */
7856 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7857 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7858 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7859 /* Rear Pin: output 1 (0x0d) */
7860 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7861 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7862 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7863 /* CLFE Pin: output 2 (0x0e) */
7864 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7865 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7866 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7867 /* Side Pin: output 3 (0x0f) */
7868 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7869 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7870 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7871 /* Mic (rear) pin: input vref at 80% */
7872 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7873 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7874 /* Front Mic pin: input vref at 80% */
7875 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7876 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7877 /* Line In pin: input */
7878 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7879 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7880
7881 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7882 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01007883 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007884 /* Input mixer2 */
7885 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007886 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01007887 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007888 /* ADC2: mute amp left and right */
7889 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7890 /* ADC3: mute amp left and right */
7891 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7892
7893 { }
7894};
7895
7896static struct hda_verb alc885_init_input_verbs[] = {
7897 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7898 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7899 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7900 { }
7901};
7902
7903
7904/* Unmute Selector 24h and set the default input to front mic */
7905static struct hda_verb alc889_init_input_verbs[] = {
7906 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7907 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7908 { }
7909};
7910
7911
Takashi Iwai4953550a2009-06-30 15:28:30 +02007912#define alc883_init_verbs alc882_base_init_verbs
7913
Tobin Davis9102cd12006-12-15 10:02:12 +01007914/* Mac Pro test */
7915static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7916 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7917 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7918 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7919 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7920 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007921 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007922 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7923 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007924 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007925 { } /* end */
7926};
7927
7928static struct hda_verb alc882_macpro_init_verbs[] = {
7929 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7930 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7931 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7933 /* Front Pin: output 0 (0x0c) */
7934 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7935 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7936 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7937 /* Front Mic pin: input vref at 80% */
7938 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7939 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7940 /* Speaker: output */
7941 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7942 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7943 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7944 /* Headphone output (output 0 - 0x0c) */
7945 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7946 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7947 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7948
7949 /* FIXME: use matrix-type input source selection */
7950 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7951 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7952 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7953 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7954 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7955 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7956 /* Input mixer2 */
7957 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7958 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7959 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7960 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7961 /* Input mixer3 */
7962 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7963 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7964 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7965 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7966 /* ADC1: mute amp left and right */
7967 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7968 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7969 /* ADC2: mute amp left and right */
7970 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7971 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7972 /* ADC3: mute amp left and right */
7973 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7974 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7975
7976 { }
7977};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007978
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007979/* Macbook 5,1 */
7980static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007981 /* DACs */
7982 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7983 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7984 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7985 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007986 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007987 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7988 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7989 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007990 /* Surround mixer */
7991 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7992 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7993 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7994 /* LFE mixer */
7995 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7996 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7997 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7998 /* HP mixer */
7999 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8000 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8001 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8002 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008003 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8004 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008005 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8006 /* LFE Pin (0x0e) */
8007 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8008 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8009 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8010 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008011 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8012 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008013 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308014 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008015 /* Front Mic pin: input vref at 80% */
8016 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8017 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8018 /* Line In pin */
8019 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8020 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8021
Alex Murrayb8f171e2010-06-14 12:08:43 +09308022 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8023 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8024 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008025 { }
8026};
8027
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008028/* Macmini 3,1 */
8029static struct hda_verb alc885_macmini3_init_verbs[] = {
8030 /* DACs */
8031 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8032 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8033 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8034 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8035 /* Front mixer */
8036 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8037 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8038 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8039 /* Surround mixer */
8040 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8041 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8042 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8043 /* LFE mixer */
8044 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8045 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8046 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8047 /* HP mixer */
8048 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8049 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8050 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8051 /* Front Pin (0x0c) */
8052 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8053 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8054 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8055 /* LFE Pin (0x0e) */
8056 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8057 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8058 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8059 /* HP Pin (0x0f) */
8060 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8061 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8062 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8063 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8064 /* Line In pin */
8065 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8067
8068 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8069 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8070 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8071 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8072 { }
8073};
8074
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008075
8076static struct hda_verb alc885_mba21_init_verbs[] = {
8077 /*Internal and HP Speaker Mixer*/
8078 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8079 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8080 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8081 /*Internal Speaker Pin (0x0c)*/
8082 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8083 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8084 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8085 /* HP Pin: output 0 (0x0e) */
8086 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8087 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8088 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8089 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8090 /* Line in (is hp when jack connected)*/
8091 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8092 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8093
8094 { }
8095 };
8096
8097
Takashi Iwai87350ad2007-08-16 18:19:38 +02008098/* Macbook Pro rev3 */
8099static struct hda_verb alc885_mbp3_init_verbs[] = {
8100 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8101 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8102 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8103 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8104 /* Rear mixer */
8105 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8106 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8107 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008108 /* HP mixer */
8109 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8110 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8111 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008112 /* Front Pin: output 0 (0x0c) */
8113 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8114 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8115 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008116 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008117 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008118 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8119 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008120 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8121 /* Mic (rear) pin: input vref at 80% */
8122 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8123 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8124 /* Front Mic pin: input vref at 80% */
8125 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8126 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8127 /* Line In pin: use output 1 when in LineOut mode */
8128 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8129 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8130 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8131
8132 /* FIXME: use matrix-type input source selection */
8133 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8134 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8135 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8136 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8137 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8138 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8139 /* Input mixer2 */
8140 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8141 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8142 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8143 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8144 /* Input mixer3 */
8145 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8146 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8147 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8148 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8149 /* ADC1: mute amp left and right */
8150 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8151 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8152 /* ADC2: mute amp left and right */
8153 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8154 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8155 /* ADC3: mute amp left and right */
8156 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8157 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8158
8159 { }
8160};
8161
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008162/* iMac 9,1 */
8163static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008164 /* Internal Speaker Pin (0x0c) */
8165 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8166 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8167 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8168 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8169 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8170 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8171 /* HP Pin: Rear */
8172 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8173 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8174 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8175 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8176 /* Line in Rear */
8177 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8178 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8179 /* Front Mic pin: input vref at 80% */
8180 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8181 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008182 /* Rear mixer */
8183 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8184 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8185 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008186 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8187 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8188 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8189 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8190 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008191 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8192 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8193 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8194 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008195 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008196 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8197 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8198 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8199 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008200 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008201 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8202 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8203 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8204 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008205 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008206 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8207 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008208 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008209 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8210 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008211 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008212 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8213 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008214 { }
8215};
8216
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008217/* iMac 24 mixer. */
8218static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8219 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8220 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8221 { } /* end */
8222};
8223
8224/* iMac 24 init verbs. */
8225static struct hda_verb alc885_imac24_init_verbs[] = {
8226 /* Internal speakers: output 0 (0x0c) */
8227 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8228 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8229 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8230 /* Internal speakers: output 0 (0x0c) */
8231 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8232 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8233 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8234 /* Headphone: output 0 (0x0c) */
8235 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8236 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8237 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8238 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8239 /* Front Mic: input vref at 80% */
8240 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8241 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8242 { }
8243};
8244
8245/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008246static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008247{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008248 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008249
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008250 spec->autocfg.hp_pins[0] = 0x14;
8251 spec->autocfg.speaker_pins[0] = 0x18;
8252 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008253}
8254
Takashi Iwai9d54f082010-02-22 08:34:40 +01008255#define alc885_mb5_setup alc885_imac24_setup
8256#define alc885_macmini3_setup alc885_imac24_setup
8257
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008258/* Macbook Air 2,1 */
8259static void alc885_mba21_setup(struct hda_codec *codec)
8260{
8261 struct alc_spec *spec = codec->spec;
8262
8263 spec->autocfg.hp_pins[0] = 0x14;
8264 spec->autocfg.speaker_pins[0] = 0x18;
8265}
8266
8267
8268
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008269static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008270{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008271 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008272
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008273 spec->autocfg.hp_pins[0] = 0x15;
8274 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008275}
8276
Takashi Iwai9d54f082010-02-22 08:34:40 +01008277static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308278{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008279 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308280
Takashi Iwai9d54f082010-02-22 08:34:40 +01008281 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008282 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008283 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008284}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008285
Kailang Yang272a5272007-05-14 11:00:38 +02008286static struct hda_verb alc882_targa_verbs[] = {
8287 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8288 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8289
8290 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8291 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008292
Kailang Yang272a5272007-05-14 11:00:38 +02008293 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8294 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8295 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8296
8297 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008298 { } /* end */
8299};
8300
8301/* toggle speaker-output according to the hp-jack state */
8302static void alc882_targa_automute(struct hda_codec *codec)
8303{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008304 struct alc_spec *spec = codec->spec;
8305 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008306 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008307 spec->jack_present ? 1 : 3);
8308}
8309
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008310static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008311{
8312 struct alc_spec *spec = codec->spec;
8313
8314 spec->autocfg.hp_pins[0] = 0x14;
8315 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008316}
8317
8318static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8319{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008320 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008321 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008322}
8323
8324static struct hda_verb alc882_asus_a7j_verbs[] = {
8325 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8326 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8327
8328 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8329 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8330 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008331
Kailang Yang272a5272007-05-14 11:00:38 +02008332 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8333 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8334 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8335
8336 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8337 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8338 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8339 { } /* end */
8340};
8341
Takashi Iwai914759b2007-09-06 14:52:04 +02008342static struct hda_verb alc882_asus_a7m_verbs[] = {
8343 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8344 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8345
8346 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8347 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8348 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008349
Takashi Iwai914759b2007-09-06 14:52:04 +02008350 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8351 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8352 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8353
8354 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8355 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8356 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8357 { } /* end */
8358};
8359
Tobin Davis9102cd12006-12-15 10:02:12 +01008360static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8361{
8362 unsigned int gpiostate, gpiomask, gpiodir;
8363
8364 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8365 AC_VERB_GET_GPIO_DATA, 0);
8366
8367 if (!muted)
8368 gpiostate |= (1 << pin);
8369 else
8370 gpiostate &= ~(1 << pin);
8371
8372 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8373 AC_VERB_GET_GPIO_MASK, 0);
8374 gpiomask |= (1 << pin);
8375
8376 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8377 AC_VERB_GET_GPIO_DIRECTION, 0);
8378 gpiodir |= (1 << pin);
8379
8380
8381 snd_hda_codec_write(codec, codec->afg, 0,
8382 AC_VERB_SET_GPIO_MASK, gpiomask);
8383 snd_hda_codec_write(codec, codec->afg, 0,
8384 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8385
8386 msleep(1);
8387
8388 snd_hda_codec_write(codec, codec->afg, 0,
8389 AC_VERB_SET_GPIO_DATA, gpiostate);
8390}
8391
Takashi Iwai7debbe52007-08-16 15:01:03 +02008392/* set up GPIO at initialization */
8393static void alc885_macpro_init_hook(struct hda_codec *codec)
8394{
8395 alc882_gpio_mute(codec, 0, 0);
8396 alc882_gpio_mute(codec, 1, 0);
8397}
8398
8399/* set up GPIO and update auto-muting at initialization */
8400static void alc885_imac24_init_hook(struct hda_codec *codec)
8401{
8402 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008403 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008404}
8405
Kailang Yangdf694da2005-12-05 19:42:22 +01008406/*
8407 * generic initialization of ADC, input mixers and output mixers
8408 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008409static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008410 /*
8411 * Unmute ADC0-2 and set the default input to mic-in
8412 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008413 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8414 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8415 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8416 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8417
Kailang Yangdf694da2005-12-05 19:42:22 +01008418 /*
8419 * Set up output mixers (0x0c - 0x0f)
8420 */
8421 /* set vol=0 to output mixers */
8422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8423 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8424 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8425 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8426 /* set up input amps for analog loopback */
8427 /* Amp Indices: DAC = 0, mixer = 1 */
8428 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8429 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8430 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8431 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8432 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8433 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8434 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8435 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8436 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8437 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8438
8439 /* FIXME: use matrix-type input source selection */
8440 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008441 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008442 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008443 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008444 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008445 { }
8446};
8447
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008448/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8449static struct hda_verb alc889A_mb31_ch2_init[] = {
8450 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8451 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8452 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8453 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8454 { } /* end */
8455};
8456
8457/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8458static struct hda_verb alc889A_mb31_ch4_init[] = {
8459 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8460 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8461 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8462 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8463 { } /* end */
8464};
8465
8466/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8467static struct hda_verb alc889A_mb31_ch5_init[] = {
8468 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8469 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8470 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8471 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8472 { } /* end */
8473};
8474
8475/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8476static struct hda_verb alc889A_mb31_ch6_init[] = {
8477 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8478 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8479 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8480 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8481 { } /* end */
8482};
8483
8484static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8485 { 2, alc889A_mb31_ch2_init },
8486 { 4, alc889A_mb31_ch4_init },
8487 { 5, alc889A_mb31_ch5_init },
8488 { 6, alc889A_mb31_ch6_init },
8489};
8490
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008491static struct hda_verb alc883_medion_eapd_verbs[] = {
8492 /* eanable EAPD on medion laptop */
8493 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8494 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8495 { }
8496};
8497
Takashi Iwai4953550a2009-06-30 15:28:30 +02008498#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008499
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008500static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8501 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8502 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8503 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8504 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8505 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8506 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8508 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8509 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8510 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8511 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8512 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8513 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008514 { } /* end */
8515};
8516
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008517static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008518 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8519 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8520 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8521 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8522 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8523 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8524 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8525 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8526 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8527 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008528 { } /* end */
8529};
8530
Jiang zhefb97dc62008-03-06 11:07:11 +01008531static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8532 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8533 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8534 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8535 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8536 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8537 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8538 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8539 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8540 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8541 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008542 { } /* end */
8543};
8544
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008545static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8546 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8547 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8548 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8549 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8550 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8551 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8552 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8553 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008554 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008555 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8556 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008557 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008558 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008559 { } /* end */
8560};
8561
8562static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8563 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8564 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8565 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8566 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8567 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8568 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8569 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8570 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8571 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8572 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8573 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8574 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8575 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8576 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008577 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008578 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8579 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008580 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008581 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008582 { } /* end */
8583};
8584
Jiang zhe17bba1b2008-06-04 12:11:07 +02008585static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8586 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8587 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8588 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8589 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8590 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8591 HDA_OUTPUT),
8592 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8593 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8594 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8595 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8596 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8597 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8598 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8599 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8600 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8601 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8602 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8603 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8604 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8605 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008606 { } /* end */
8607};
8608
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008609static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8610 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8611 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8612 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8613 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8614 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8615 HDA_OUTPUT),
8616 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8617 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8618 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8619 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8620 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8621 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8622 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8623 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8624 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8625 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8626 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8627 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8628 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8629 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8630 { } /* end */
8631};
8632
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008633static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008634 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008635 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008636 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008637 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008638 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8639 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008640 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8641 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008642 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8643 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8644 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8645 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8646 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8647 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008648 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008649 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8650 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008651 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008652 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008653 { } /* end */
8654};
8655
Sasha Alexandrc2592492009-06-16 14:52:54 -04008656static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008657 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008658 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008659 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008660 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008661 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8662 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8663 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8664 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8665 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8666 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8667 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8668 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8669 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8670 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8671 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008672 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008673 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008674 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008675};
Kailang Yangccc656c2006-10-17 12:32:26 +02008676
Sasha Alexandrc2592492009-06-16 14:52:54 -04008677static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008678 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008679 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008680 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008681 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008682 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8683 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8684 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008685 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008686 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008687 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8688 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8689 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008690 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008691};
Kailang Yangccc656c2006-10-17 12:32:26 +02008692
Takashi Iwaib99dba32009-09-17 18:23:00 +02008693static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8694 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8695 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8696 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8697 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8698 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8699 { } /* end */
8700};
8701
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008702static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8703 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8704 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008705 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8706 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008707 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8708 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8709 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8710 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008711 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008712};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008713
Kailang Yang272a5272007-05-14 11:00:38 +02008714static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8715 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8716 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8717 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8718 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8719 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8720 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8721 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson150b4322010-07-29 14:46:42 +02008722 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8723 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008724 { } /* end */
8725};
8726
8727static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8728 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8729 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8730 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8731 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8732 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8733 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8734 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8735 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8736 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008737 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008738};
Kailang Yang272a5272007-05-14 11:00:38 +02008739
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02008740static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
8741 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8742 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8743 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8744 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
8745 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
8746 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
8747 { } /* end */
8748};
8749
8750static struct hda_verb alc883_medion_wim2160_verbs[] = {
8751 /* Unmute front mixer */
8752 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8753 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8754
8755 /* Set speaker pin to front mixer */
8756 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8757
8758 /* Init headphone pin */
8759 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8760 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8761 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8762 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8763
8764 { } /* end */
8765};
8766
8767/* toggle speaker-output according to the hp-jack state */
8768static void alc883_medion_wim2160_setup(struct hda_codec *codec)
8769{
8770 struct alc_spec *spec = codec->spec;
8771
8772 spec->autocfg.hp_pins[0] = 0x1a;
8773 spec->autocfg.speaker_pins[0] = 0x15;
8774}
8775
Tobin Davis2880a862007-08-07 11:50:26 +02008776static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008777 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8778 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008779 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008780 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8781 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008782 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8783 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8784 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008785 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008786};
Tobin Davis2880a862007-08-07 11:50:26 +02008787
Tony Vroond2fd4b02009-06-21 00:40:10 +01008788static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8789 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008790 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008791 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8792 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008793 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8794 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8795 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8796 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8797 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8798 { } /* end */
8799};
8800
Kailang Yange2757d52008-08-26 13:17:46 +02008801static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8802 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8803 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8804 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8805 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8806 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8807 0x0d, 1, 0x0, HDA_OUTPUT),
8808 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8809 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8810 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8811 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8812 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008813 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8814 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8815 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8816 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8817 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8818 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8819 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8820 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8821 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8822 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008823 { } /* end */
8824};
8825
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008826static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8827 /* Output mixers */
8828 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8829 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8830 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8831 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8832 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8833 HDA_OUTPUT),
8834 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8835 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8836 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8837 /* Output switches */
8838 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8839 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8840 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8841 /* Boost mixers */
8842 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8843 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8844 /* Input mixers */
8845 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8846 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8847 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8848 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8849 { } /* end */
8850};
8851
Guido Günther3e1647c2009-06-05 00:47:26 +02008852static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8853 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8854 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8855 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8856 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8857 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8858 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8859 { } /* end */
8860};
8861
Kailang Yange2757d52008-08-26 13:17:46 +02008862static struct hda_bind_ctls alc883_bind_cap_vol = {
8863 .ops = &snd_hda_bind_vol,
8864 .values = {
8865 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8866 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8867 0
8868 },
8869};
8870
8871static struct hda_bind_ctls alc883_bind_cap_switch = {
8872 .ops = &snd_hda_bind_sw,
8873 .values = {
8874 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8875 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8876 0
8877 },
8878};
8879
8880static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8881 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8882 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8883 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8884 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8885 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8886 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8887 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8888 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008889 { } /* end */
8890};
8891
8892static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008893 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8894 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8895 {
8896 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8897 /* .name = "Capture Source", */
8898 .name = "Input Source",
8899 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008900 .info = alc_mux_enum_info,
8901 .get = alc_mux_enum_get,
8902 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008903 },
8904 { } /* end */
8905};
8906
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008907static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8908 {
8909 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8910 .name = "Channel Mode",
8911 .info = alc_ch_mode_info,
8912 .get = alc_ch_mode_get,
8913 .put = alc_ch_mode_put,
8914 },
8915 { } /* end */
8916};
8917
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008918/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008919static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008920{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008921 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008922
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008923 spec->autocfg.hp_pins[0] = 0x15;
8924 spec->autocfg.speaker_pins[0] = 0x14;
8925 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008926}
8927
8928/* auto-toggle front mic */
8929/*
8930static void alc883_mitac_mic_automute(struct hda_codec *codec)
8931{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008932 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008933
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008934 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8935}
8936*/
8937
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008938static struct hda_verb alc883_mitac_verbs[] = {
8939 /* HP */
8940 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8941 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8942 /* Subwoofer */
8943 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8944 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8945
8946 /* enable unsolicited event */
8947 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8948 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8949
8950 { } /* end */
8951};
8952
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308953static struct hda_verb alc883_clevo_m540r_verbs[] = {
8954 /* HP */
8955 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8956 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8957 /* Int speaker */
8958 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8959
8960 /* enable unsolicited event */
8961 /*
8962 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8963 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8964 */
8965
8966 { } /* end */
8967};
8968
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008969static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008970 /* HP */
8971 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8972 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8973 /* Int speaker */
8974 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8975 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8976
8977 /* enable unsolicited event */
8978 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008979 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008980
8981 { } /* end */
8982};
8983
Jiang zhefb97dc62008-03-06 11:07:11 +01008984static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8985 /* HP */
8986 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8987 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8988 /* Subwoofer */
8989 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8990 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8991
8992 /* enable unsolicited event */
8993 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8994
8995 { } /* end */
8996};
8997
Sasha Alexandrc2592492009-06-16 14:52:54 -04008998static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008999 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9000 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9001
9002 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9003 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009004
David Heidelberger64a8be72009-06-08 16:15:18 +02009005/* Connect Line-Out side jack (SPDIF) to Side */
9006 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9007 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9008 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9009/* Connect Mic jack to CLFE */
9010 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9011 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9012 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9013/* Connect Line-in jack to Surround */
9014 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9015 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9016 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9017/* Connect HP out jack to Front */
9018 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9019 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9020 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009021
9022 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009023
9024 { } /* end */
9025};
9026
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009027static struct hda_verb alc883_lenovo_101e_verbs[] = {
9028 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9029 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9030 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9031 { } /* end */
9032};
9033
Kailang Yang272a5272007-05-14 11:00:38 +02009034static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9035 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9036 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9037 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9038 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9039 { } /* end */
9040};
9041
9042static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9043 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9044 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9045 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9046 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9047 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9048 { } /* end */
9049};
9050
Kailang Yang189609a2007-08-20 11:31:23 +02009051static struct hda_verb alc883_haier_w66_verbs[] = {
9052 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9053 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9054
9055 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9056
9057 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9058 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9059 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9060 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9061 { } /* end */
9062};
9063
Kailang Yange2757d52008-08-26 13:17:46 +02009064static struct hda_verb alc888_lenovo_sky_verbs[] = {
9065 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9066 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9067 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9068 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9069 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9070 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9071 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9072 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9073 { } /* end */
9074};
9075
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009076static struct hda_verb alc888_6st_dell_verbs[] = {
9077 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9078 { }
9079};
9080
Guido Günther3e1647c2009-06-05 00:47:26 +02009081static struct hda_verb alc883_vaiott_verbs[] = {
9082 /* HP */
9083 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9084 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9085
9086 /* enable unsolicited event */
9087 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9088
9089 { } /* end */
9090};
9091
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009092static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009093{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009094 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009095
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009096 spec->autocfg.hp_pins[0] = 0x1b;
9097 spec->autocfg.speaker_pins[0] = 0x14;
9098 spec->autocfg.speaker_pins[1] = 0x16;
9099 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009100}
9101
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009102static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009103 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009104 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9105 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009106 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009107 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009108};
9109
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009110/*
9111 * 2ch mode
9112 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009113static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009114 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9115 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9116 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9117 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009118 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009119};
9120
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009121/*
9122 * 4ch mode
9123 */
9124static struct hda_verb alc888_3st_hp_4ch_init[] = {
9125 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9126 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9127 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9128 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9129 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9130 { } /* end */
9131};
9132
9133/*
9134 * 6ch mode
9135 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009136static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009137 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9138 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009139 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009140 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9141 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009142 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9143 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009144};
9145
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009146static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009147 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009148 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009149 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009150};
9151
Kailang Yang272a5272007-05-14 11:00:38 +02009152/* toggle front-jack and RCA according to the hp-jack state */
9153static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9154{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009155 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009156
Takashi Iwai47fd8302007-08-10 17:11:07 +02009157 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9158 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9159 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9160 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009161}
9162
9163/* toggle RCA according to the front-jack state */
9164static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9165{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009166 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009167
Takashi Iwai47fd8302007-08-10 17:11:07 +02009168 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9169 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009170}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009171
Kailang Yang272a5272007-05-14 11:00:38 +02009172static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9173 unsigned int res)
9174{
9175 if ((res >> 26) == ALC880_HP_EVENT)
9176 alc888_lenovo_ms7195_front_automute(codec);
9177 if ((res >> 26) == ALC880_FRONT_EVENT)
9178 alc888_lenovo_ms7195_rca_automute(codec);
9179}
9180
9181static struct hda_verb alc883_medion_md2_verbs[] = {
9182 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9183 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9184
9185 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9186
9187 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9188 { } /* end */
9189};
9190
9191/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009192static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009193{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009194 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009195
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009196 spec->autocfg.hp_pins[0] = 0x14;
9197 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009198}
9199
Kailang Yangccc656c2006-10-17 12:32:26 +02009200/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009201#define alc883_targa_init_hook alc882_targa_init_hook
9202#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009203
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009204static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
9205{
9206 unsigned int present;
9207
Takashi Iwaid56757a2009-11-18 08:00:14 +01009208 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009209 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
9210 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9211}
9212
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009213static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009214{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009215 struct alc_spec *spec = codec->spec;
9216
9217 spec->autocfg.hp_pins[0] = 0x15;
9218 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009219}
9220
9221static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9222{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009223 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009224 alc883_clevo_m720_mic_automute(codec);
9225}
9226
9227static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009228 unsigned int res)
9229{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009230 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009231 case ALC880_MIC_EVENT:
9232 alc883_clevo_m720_mic_automute(codec);
9233 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009234 default:
9235 alc_automute_amp_unsol_event(codec, res);
9236 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009237 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009238}
9239
Jiang zhefb97dc62008-03-06 11:07:11 +01009240/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009241static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009242{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009243 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009244
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009245 spec->autocfg.hp_pins[0] = 0x14;
9246 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009247}
9248
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009249static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009250{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009251 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009252
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009253 spec->autocfg.hp_pins[0] = 0x1b;
9254 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009255}
9256
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009257static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9258{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009259 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009260
Takashi Iwai47fd8302007-08-10 17:11:07 +02009261 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9262 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009263}
9264
9265static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9266{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009267 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009268
Takashi Iwai47fd8302007-08-10 17:11:07 +02009269 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9270 HDA_AMP_MUTE, bits);
9271 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9272 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009273}
9274
9275static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9276 unsigned int res)
9277{
9278 if ((res >> 26) == ALC880_HP_EVENT)
9279 alc883_lenovo_101e_all_automute(codec);
9280 if ((res >> 26) == ALC880_FRONT_EVENT)
9281 alc883_lenovo_101e_ispeaker_automute(codec);
9282}
9283
Takashi Iwai676a9b52007-08-16 15:23:35 +02009284/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009285static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009286{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009287 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009288
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009289 spec->autocfg.hp_pins[0] = 0x14;
9290 spec->autocfg.speaker_pins[0] = 0x15;
9291 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009292}
9293
Kailang Yangd1a991a2007-08-15 16:21:59 +02009294static struct hda_verb alc883_acer_eapd_verbs[] = {
9295 /* HP Pin: output 0 (0x0c) */
9296 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9297 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9298 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9299 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009300 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9301 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009302 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009303 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9304 /* eanable EAPD on medion laptop */
9305 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9306 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009307 /* enable unsolicited event */
9308 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009309 { }
9310};
9311
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009312static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
9313 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9314 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9315 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9316 { } /* end */
9317};
9318
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009319static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009320{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009321 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009322
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009323 spec->autocfg.hp_pins[0] = 0x1b;
9324 spec->autocfg.speaker_pins[0] = 0x14;
9325 spec->autocfg.speaker_pins[1] = 0x15;
9326 spec->autocfg.speaker_pins[2] = 0x16;
9327 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009328}
9329
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009330static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009331{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009332 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009333
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009334 spec->autocfg.hp_pins[0] = 0x1b;
9335 spec->autocfg.speaker_pins[0] = 0x14;
9336 spec->autocfg.speaker_pins[1] = 0x15;
9337 spec->autocfg.speaker_pins[2] = 0x16;
9338 spec->autocfg.speaker_pins[3] = 0x17;
9339 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009340}
9341
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009342static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009343{
9344 struct alc_spec *spec = codec->spec;
9345
9346 spec->autocfg.hp_pins[0] = 0x15;
9347 spec->autocfg.speaker_pins[0] = 0x14;
9348 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009349}
9350
Kailang Yange2757d52008-08-26 13:17:46 +02009351static struct hda_verb alc888_asus_m90v_verbs[] = {
9352 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9353 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9354 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9355 /* enable unsolicited event */
9356 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9357 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9358 { } /* end */
9359};
9360
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009361static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009362{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009363 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009364
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009365 spec->autocfg.hp_pins[0] = 0x1b;
9366 spec->autocfg.speaker_pins[0] = 0x14;
9367 spec->autocfg.speaker_pins[1] = 0x15;
9368 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009369 spec->ext_mic.pin = 0x18;
9370 spec->int_mic.pin = 0x19;
9371 spec->ext_mic.mux_idx = 0;
9372 spec->int_mic.mux_idx = 1;
9373 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009374}
9375
9376static struct hda_verb alc888_asus_eee1601_verbs[] = {
9377 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9378 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9379 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9382 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9383 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9384 /* enable unsolicited event */
9385 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9386 { } /* end */
9387};
9388
Kailang Yange2757d52008-08-26 13:17:46 +02009389static void alc883_eee1601_inithook(struct hda_codec *codec)
9390{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009391 struct alc_spec *spec = codec->spec;
9392
9393 spec->autocfg.hp_pins[0] = 0x14;
9394 spec->autocfg.speaker_pins[0] = 0x1b;
9395 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009396}
9397
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009398static struct hda_verb alc889A_mb31_verbs[] = {
9399 /* Init rear pin (used as headphone output) */
9400 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9401 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9402 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9403 /* Init line pin (used as output in 4ch and 6ch mode) */
9404 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9405 /* Init line 2 pin (used as headphone out by default) */
9406 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9407 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9408 { } /* end */
9409};
9410
9411/* Mute speakers according to the headphone jack state */
9412static void alc889A_mb31_automute(struct hda_codec *codec)
9413{
9414 unsigned int present;
9415
9416 /* Mute only in 2ch or 4ch mode */
9417 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9418 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009419 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009420 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9421 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9422 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9423 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9424 }
9425}
9426
9427static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9428{
9429 if ((res >> 26) == ALC880_HP_EVENT)
9430 alc889A_mb31_automute(codec);
9431}
9432
Takashi Iwai4953550a2009-06-30 15:28:30 +02009433
Takashi Iwaicb53c622007-08-10 17:21:45 +02009434#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02009435#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009436#endif
9437
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009438/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009439#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9440#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9441#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9442#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9443
9444static hda_nid_t alc883_slave_dig_outs[] = {
9445 ALC1200_DIGOUT_NID, 0,
9446};
9447
9448static hda_nid_t alc1200_slave_dig_outs[] = {
9449 ALC883_DIGOUT_NID, 0,
9450};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009451
9452/*
9453 * configuration and preset
9454 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009455static const char *alc882_models[ALC882_MODEL_LAST] = {
9456 [ALC882_3ST_DIG] = "3stack-dig",
9457 [ALC882_6ST_DIG] = "6stack-dig",
9458 [ALC882_ARIMA] = "arima",
9459 [ALC882_W2JC] = "w2jc",
9460 [ALC882_TARGA] = "targa",
9461 [ALC882_ASUS_A7J] = "asus-a7j",
9462 [ALC882_ASUS_A7M] = "asus-a7m",
9463 [ALC885_MACPRO] = "macpro",
9464 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009465 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009466 [ALC885_MBA21] = "mba21",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009467 [ALC885_MBP3] = "mbp3",
9468 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009469 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009470 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009471 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9472 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009473 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009474 [ALC883_TARGA_DIG] = "targa-dig",
9475 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009476 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009477 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009478 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009479 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009480 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009481 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009482 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009483 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02009484 [ALC883_MEDION_MD2] = "medion-md2",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009485 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009486 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009487 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009488 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9489 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009490 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009491 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009492 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009493 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009494 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309495 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009496 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009497 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009498 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009499 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009500 [ALC889A_INTEL] = "intel-alc889a",
9501 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009502 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009503 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009504 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009505 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009506};
9507
Takashi Iwai4953550a2009-06-30 15:28:30 +02009508static struct snd_pci_quirk alc882_cfg_tbl[] = {
9509 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9510
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009511 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009512 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009513 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009514 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9515 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009516 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009517 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9518 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009519 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009520 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009521 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9522 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009523 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9524 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009525 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9526 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009527 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009528 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009529 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009530 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009531 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9532 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009533 /* default Acer -- disabled as it causes more problems.
9534 * model=auto should work fine now
9535 */
9536 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009537
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009538 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009539
Tobin Davisfebe3372007-06-12 11:27:46 +02009540 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009541 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9542 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009543 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009544 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009545 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009546
9547 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9548 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9549 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009550 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009551 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9552 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9553 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009554 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009555 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009556 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009557 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009558
9559 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009560 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009561 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009562 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009563 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9564 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009565 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009566 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009567 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9568
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009569 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9570 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9571 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009572 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009573 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009574 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009575 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009576 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009577 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9578 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9579 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9580 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9581 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9582 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009583 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009584 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9585 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9586 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009587 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009588 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009589 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9590 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009591 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009592 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009593 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009594 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009595 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009596 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009597 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009598 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009599 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009600
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009601 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009602 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009603 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9604 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309605 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009606 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009607 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009608 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009609 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009610 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009611 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009612 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009613 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009614 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009615 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009616 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9617 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009618 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009619 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009620 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009621 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009622 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009623
Jiang zhe17bba1b2008-06-04 12:11:07 +02009624 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9625 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009626 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009627 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9628 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9629 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009630 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009631
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009632 {}
9633};
9634
Takashi Iwai4953550a2009-06-30 15:28:30 +02009635/* codec SSID table for Intel Mac */
9636static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9637 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9638 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9639 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9640 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9641 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9642 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9643 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009644 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009645 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009646 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009647 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009648 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9649 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9650 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009651 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009652 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009653 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009654 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9655 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +02009656 */
9657 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009658 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009659 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009660 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009661};
9662
Takashi Iwai4953550a2009-06-30 15:28:30 +02009663static struct alc_config_preset alc882_presets[] = {
9664 [ALC882_3ST_DIG] = {
9665 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009666 .init_verbs = { alc882_base_init_verbs,
9667 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009668 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9669 .dac_nids = alc882_dac_nids,
9670 .dig_out_nid = ALC882_DIGOUT_NID,
9671 .dig_in_nid = ALC882_DIGIN_NID,
9672 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9673 .channel_mode = alc882_ch_modes,
9674 .need_dac_fix = 1,
9675 .input_mux = &alc882_capture_source,
9676 },
9677 [ALC882_6ST_DIG] = {
9678 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009679 .init_verbs = { alc882_base_init_verbs,
9680 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009681 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9682 .dac_nids = alc882_dac_nids,
9683 .dig_out_nid = ALC882_DIGOUT_NID,
9684 .dig_in_nid = ALC882_DIGIN_NID,
9685 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9686 .channel_mode = alc882_sixstack_modes,
9687 .input_mux = &alc882_capture_source,
9688 },
9689 [ALC882_ARIMA] = {
9690 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009691 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9692 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009693 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9694 .dac_nids = alc882_dac_nids,
9695 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9696 .channel_mode = alc882_sixstack_modes,
9697 .input_mux = &alc882_capture_source,
9698 },
9699 [ALC882_W2JC] = {
9700 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009701 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9702 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009703 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9704 .dac_nids = alc882_dac_nids,
9705 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9706 .channel_mode = alc880_threestack_modes,
9707 .need_dac_fix = 1,
9708 .input_mux = &alc882_capture_source,
9709 .dig_out_nid = ALC882_DIGOUT_NID,
9710 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009711 [ALC885_MBA21] = {
9712 .mixers = { alc885_mba21_mixer },
9713 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9714 .num_dacs = 2,
9715 .dac_nids = alc882_dac_nids,
9716 .channel_mode = alc885_mba21_ch_modes,
9717 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9718 .input_mux = &alc882_capture_source,
9719 .unsol_event = alc_automute_amp_unsol_event,
9720 .setup = alc885_mba21_setup,
9721 .init_hook = alc_automute_amp,
9722 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009723 [ALC885_MBP3] = {
9724 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9725 .init_verbs = { alc885_mbp3_init_verbs,
9726 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009727 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009728 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009729 .hp_nid = 0x04,
9730 .channel_mode = alc885_mbp_4ch_modes,
9731 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009732 .input_mux = &alc882_capture_source,
9733 .dig_out_nid = ALC882_DIGOUT_NID,
9734 .dig_in_nid = ALC882_DIGIN_NID,
9735 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009736 .setup = alc885_mbp3_setup,
9737 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009738 },
9739 [ALC885_MB5] = {
9740 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9741 .init_verbs = { alc885_mb5_init_verbs,
9742 alc880_gpio1_init_verbs },
9743 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9744 .dac_nids = alc882_dac_nids,
9745 .channel_mode = alc885_mb5_6ch_modes,
9746 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9747 .input_mux = &mb5_capture_source,
9748 .dig_out_nid = ALC882_DIGOUT_NID,
9749 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009750 .unsol_event = alc_automute_amp_unsol_event,
9751 .setup = alc885_mb5_setup,
9752 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009753 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009754 [ALC885_MACMINI3] = {
9755 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
9756 .init_verbs = { alc885_macmini3_init_verbs,
9757 alc880_gpio1_init_verbs },
9758 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9759 .dac_nids = alc882_dac_nids,
9760 .channel_mode = alc885_macmini3_6ch_modes,
9761 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
9762 .input_mux = &macmini3_capture_source,
9763 .dig_out_nid = ALC882_DIGOUT_NID,
9764 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009765 .unsol_event = alc_automute_amp_unsol_event,
9766 .setup = alc885_macmini3_setup,
9767 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009768 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009769 [ALC885_MACPRO] = {
9770 .mixers = { alc882_macpro_mixer },
9771 .init_verbs = { alc882_macpro_init_verbs },
9772 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9773 .dac_nids = alc882_dac_nids,
9774 .dig_out_nid = ALC882_DIGOUT_NID,
9775 .dig_in_nid = ALC882_DIGIN_NID,
9776 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9777 .channel_mode = alc882_ch_modes,
9778 .input_mux = &alc882_capture_source,
9779 .init_hook = alc885_macpro_init_hook,
9780 },
9781 [ALC885_IMAC24] = {
9782 .mixers = { alc885_imac24_mixer },
9783 .init_verbs = { alc885_imac24_init_verbs },
9784 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9785 .dac_nids = alc882_dac_nids,
9786 .dig_out_nid = ALC882_DIGOUT_NID,
9787 .dig_in_nid = ALC882_DIGIN_NID,
9788 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9789 .channel_mode = alc882_ch_modes,
9790 .input_mux = &alc882_capture_source,
9791 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009792 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009793 .init_hook = alc885_imac24_init_hook,
9794 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009795 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009796 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009797 .init_verbs = { alc885_imac91_init_verbs,
9798 alc880_gpio1_init_verbs },
9799 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9800 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07009801 .channel_mode = alc885_mba21_ch_modes,
9802 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9803 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009804 .dig_out_nid = ALC882_DIGOUT_NID,
9805 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +01009806 .unsol_event = alc_automute_amp_unsol_event,
9807 .setup = alc885_imac91_setup,
9808 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009809 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009810 [ALC882_TARGA] = {
9811 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009812 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009813 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009814 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9815 .dac_nids = alc882_dac_nids,
9816 .dig_out_nid = ALC882_DIGOUT_NID,
9817 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9818 .adc_nids = alc882_adc_nids,
9819 .capsrc_nids = alc882_capsrc_nids,
9820 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9821 .channel_mode = alc882_3ST_6ch_modes,
9822 .need_dac_fix = 1,
9823 .input_mux = &alc882_capture_source,
9824 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009825 .setup = alc882_targa_setup,
9826 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009827 },
9828 [ALC882_ASUS_A7J] = {
9829 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009830 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9831 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009832 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9833 .dac_nids = alc882_dac_nids,
9834 .dig_out_nid = ALC882_DIGOUT_NID,
9835 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9836 .adc_nids = alc882_adc_nids,
9837 .capsrc_nids = alc882_capsrc_nids,
9838 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9839 .channel_mode = alc882_3ST_6ch_modes,
9840 .need_dac_fix = 1,
9841 .input_mux = &alc882_capture_source,
9842 },
9843 [ALC882_ASUS_A7M] = {
9844 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009845 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9846 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009847 alc882_asus_a7m_verbs },
9848 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9849 .dac_nids = alc882_dac_nids,
9850 .dig_out_nid = ALC882_DIGOUT_NID,
9851 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9852 .channel_mode = alc880_threestack_modes,
9853 .need_dac_fix = 1,
9854 .input_mux = &alc882_capture_source,
9855 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009856 [ALC883_3ST_2ch_DIG] = {
9857 .mixers = { alc883_3ST_2ch_mixer },
9858 .init_verbs = { alc883_init_verbs },
9859 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9860 .dac_nids = alc883_dac_nids,
9861 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009862 .dig_in_nid = ALC883_DIGIN_NID,
9863 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9864 .channel_mode = alc883_3ST_2ch_modes,
9865 .input_mux = &alc883_capture_source,
9866 },
9867 [ALC883_3ST_6ch_DIG] = {
9868 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9869 .init_verbs = { alc883_init_verbs },
9870 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9871 .dac_nids = alc883_dac_nids,
9872 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009873 .dig_in_nid = ALC883_DIGIN_NID,
9874 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9875 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009876 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009877 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009878 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009879 [ALC883_3ST_6ch] = {
9880 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9881 .init_verbs = { alc883_init_verbs },
9882 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9883 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009884 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9885 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009886 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009887 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009888 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009889 [ALC883_3ST_6ch_INTEL] = {
9890 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9891 .init_verbs = { alc883_init_verbs },
9892 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9893 .dac_nids = alc883_dac_nids,
9894 .dig_out_nid = ALC883_DIGOUT_NID,
9895 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009896 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009897 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9898 .channel_mode = alc883_3ST_6ch_intel_modes,
9899 .need_dac_fix = 1,
9900 .input_mux = &alc883_3stack_6ch_intel,
9901 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009902 [ALC889A_INTEL] = {
9903 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009904 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9905 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009906 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9907 .dac_nids = alc883_dac_nids,
9908 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9909 .adc_nids = alc889_adc_nids,
9910 .dig_out_nid = ALC883_DIGOUT_NID,
9911 .dig_in_nid = ALC883_DIGIN_NID,
9912 .slave_dig_outs = alc883_slave_dig_outs,
9913 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9914 .channel_mode = alc889_8ch_intel_modes,
9915 .capsrc_nids = alc889_capsrc_nids,
9916 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009917 .setup = alc889_automute_setup,
9918 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009919 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009920 .need_dac_fix = 1,
9921 },
9922 [ALC889_INTEL] = {
9923 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9924 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009925 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009926 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9927 .dac_nids = alc883_dac_nids,
9928 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9929 .adc_nids = alc889_adc_nids,
9930 .dig_out_nid = ALC883_DIGOUT_NID,
9931 .dig_in_nid = ALC883_DIGIN_NID,
9932 .slave_dig_outs = alc883_slave_dig_outs,
9933 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9934 .channel_mode = alc889_8ch_intel_modes,
9935 .capsrc_nids = alc889_capsrc_nids,
9936 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009937 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009938 .init_hook = alc889_intel_init_hook,
9939 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009940 .need_dac_fix = 1,
9941 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009942 [ALC883_6ST_DIG] = {
9943 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9944 .init_verbs = { alc883_init_verbs },
9945 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9946 .dac_nids = alc883_dac_nids,
9947 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009948 .dig_in_nid = ALC883_DIGIN_NID,
9949 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9950 .channel_mode = alc883_sixstack_modes,
9951 .input_mux = &alc883_capture_source,
9952 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009953 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009954 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009955 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9956 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009957 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9958 .dac_nids = alc883_dac_nids,
9959 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009960 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9961 .channel_mode = alc883_3ST_6ch_modes,
9962 .need_dac_fix = 1,
9963 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009964 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009965 .setup = alc882_targa_setup,
9966 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009967 },
9968 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009969 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009970 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9971 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009972 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9973 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009974 .adc_nids = alc883_adc_nids_alt,
9975 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009976 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +02009977 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009978 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9979 .channel_mode = alc883_3ST_2ch_modes,
9980 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009981 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009982 .setup = alc882_targa_setup,
9983 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009984 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009985 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009986 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9987 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009988 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009989 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009990 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9991 .dac_nids = alc883_dac_nids,
9992 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9993 .adc_nids = alc883_adc_nids_rev,
9994 .capsrc_nids = alc883_capsrc_nids_rev,
9995 .dig_out_nid = ALC883_DIGOUT_NID,
9996 .dig_in_nid = ALC883_DIGIN_NID,
9997 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
9998 .channel_mode = alc883_4ST_8ch_modes,
9999 .need_dac_fix = 1,
10000 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010001 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010002 .setup = alc882_targa_setup,
10003 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010004 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010005 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010006 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010007 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10008 * and the headphone jack. Turn this on and rely on the
10009 * standard mute methods whenever the user wants to turn
10010 * these outputs off.
10011 */
10012 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10013 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10014 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010015 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10016 .channel_mode = alc883_3ST_2ch_modes,
10017 .input_mux = &alc883_capture_source,
10018 },
Tobin Davis2880a862007-08-07 11:50:26 +020010019 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010020 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010021 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010022 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10023 .dac_nids = alc883_dac_nids,
10024 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010025 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10026 .channel_mode = alc883_3ST_2ch_modes,
10027 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010028 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010029 .setup = alc883_acer_aspire_setup,
10030 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010031 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010032 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010033 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010034 alc883_chmode_mixer },
10035 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10036 alc888_acer_aspire_4930g_verbs },
10037 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10038 .dac_nids = alc883_dac_nids,
10039 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10040 .adc_nids = alc883_adc_nids_rev,
10041 .capsrc_nids = alc883_capsrc_nids_rev,
10042 .dig_out_nid = ALC883_DIGOUT_NID,
10043 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10044 .channel_mode = alc883_3ST_6ch_modes,
10045 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010046 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010047 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010048 ARRAY_SIZE(alc888_2_capture_sources),
10049 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010050 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010051 .setup = alc888_acer_aspire_4930g_setup,
10052 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010053 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010054 [ALC888_ACER_ASPIRE_6530G] = {
10055 .mixers = { alc888_acer_aspire_6530_mixer },
10056 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10057 alc888_acer_aspire_6530g_verbs },
10058 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10059 .dac_nids = alc883_dac_nids,
10060 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10061 .adc_nids = alc883_adc_nids_rev,
10062 .capsrc_nids = alc883_capsrc_nids_rev,
10063 .dig_out_nid = ALC883_DIGOUT_NID,
10064 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10065 .channel_mode = alc883_3ST_2ch_modes,
10066 .num_mux_defs =
10067 ARRAY_SIZE(alc888_2_capture_sources),
10068 .input_mux = alc888_acer_aspire_6530_sources,
10069 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010070 .setup = alc888_acer_aspire_6530g_setup,
10071 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010072 },
Hector Martin3b315d72009-06-02 10:54:19 +020010073 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010074 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010075 alc883_chmode_mixer },
10076 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010077 alc889_acer_aspire_8930g_verbs,
10078 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010079 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10080 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010081 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10082 .adc_nids = alc889_adc_nids,
10083 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010084 .dig_out_nid = ALC883_DIGOUT_NID,
10085 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10086 .channel_mode = alc883_3ST_6ch_modes,
10087 .need_dac_fix = 1,
10088 .const_channel_count = 6,
10089 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010090 ARRAY_SIZE(alc889_capture_sources),
10091 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010092 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010093 .setup = alc889_acer_aspire_8930g_setup,
10094 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010095#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010096 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010097#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010098 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010099 [ALC888_ACER_ASPIRE_7730G] = {
10100 .mixers = { alc883_3ST_6ch_mixer,
10101 alc883_chmode_mixer },
10102 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10103 alc888_acer_aspire_7730G_verbs },
10104 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10105 .dac_nids = alc883_dac_nids,
10106 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10107 .adc_nids = alc883_adc_nids_rev,
10108 .capsrc_nids = alc883_capsrc_nids_rev,
10109 .dig_out_nid = ALC883_DIGOUT_NID,
10110 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10111 .channel_mode = alc883_3ST_6ch_modes,
10112 .need_dac_fix = 1,
10113 .const_channel_count = 6,
10114 .input_mux = &alc883_capture_source,
10115 .unsol_event = alc_automute_amp_unsol_event,
10116 .setup = alc888_acer_aspire_6530g_setup,
10117 .init_hook = alc_automute_amp,
10118 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010119 [ALC883_MEDION] = {
10120 .mixers = { alc883_fivestack_mixer,
10121 alc883_chmode_mixer },
10122 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010123 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010124 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10125 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010126 .adc_nids = alc883_adc_nids_alt,
10127 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010128 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010129 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10130 .channel_mode = alc883_sixstack_modes,
10131 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010132 },
Kailang Yang272a5272007-05-14 11:00:38 +020010133 [ALC883_MEDION_MD2] = {
10134 .mixers = { alc883_medion_md2_mixer},
10135 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
10136 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10137 .dac_nids = alc883_dac_nids,
10138 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010139 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10140 .channel_mode = alc883_3ST_2ch_modes,
10141 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010142 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010143 .setup = alc883_medion_md2_setup,
10144 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020010145 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010146 [ALC883_MEDION_WIM2160] = {
10147 .mixers = { alc883_medion_wim2160_mixer },
10148 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10149 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10150 .dac_nids = alc883_dac_nids,
10151 .dig_out_nid = ALC883_DIGOUT_NID,
10152 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10153 .adc_nids = alc883_adc_nids,
10154 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10155 .channel_mode = alc883_3ST_2ch_modes,
10156 .input_mux = &alc883_capture_source,
10157 .unsol_event = alc_automute_amp_unsol_event,
10158 .setup = alc883_medion_wim2160_setup,
10159 .init_hook = alc_automute_amp,
10160 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010161 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010162 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010163 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10164 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10165 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010166 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10167 .channel_mode = alc883_3ST_2ch_modes,
10168 .input_mux = &alc883_capture_source,
10169 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010170 [ALC883_CLEVO_M540R] = {
10171 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10172 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10173 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10174 .dac_nids = alc883_dac_nids,
10175 .dig_out_nid = ALC883_DIGOUT_NID,
10176 .dig_in_nid = ALC883_DIGIN_NID,
10177 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10178 .channel_mode = alc883_3ST_6ch_clevo_modes,
10179 .need_dac_fix = 1,
10180 .input_mux = &alc883_capture_source,
10181 /* This machine has the hardware HP auto-muting, thus
10182 * we need no software mute via unsol event
10183 */
10184 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010185 [ALC883_CLEVO_M720] = {
10186 .mixers = { alc883_clevo_m720_mixer },
10187 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010188 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10189 .dac_nids = alc883_dac_nids,
10190 .dig_out_nid = ALC883_DIGOUT_NID,
10191 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10192 .channel_mode = alc883_3ST_2ch_modes,
10193 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010194 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010195 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010196 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010197 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010198 [ALC883_LENOVO_101E_2ch] = {
10199 .mixers = { alc883_lenovo_101e_2ch_mixer},
10200 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10201 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10202 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010203 .adc_nids = alc883_adc_nids_alt,
10204 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010205 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010206 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10207 .channel_mode = alc883_3ST_2ch_modes,
10208 .input_mux = &alc883_lenovo_101e_capture_source,
10209 .unsol_event = alc883_lenovo_101e_unsol_event,
10210 .init_hook = alc883_lenovo_101e_all_automute,
10211 },
Kailang Yang272a5272007-05-14 11:00:38 +020010212 [ALC883_LENOVO_NB0763] = {
10213 .mixers = { alc883_lenovo_nb0763_mixer },
10214 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10215 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10216 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010217 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10218 .channel_mode = alc883_3ST_2ch_modes,
10219 .need_dac_fix = 1,
10220 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010221 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010222 .setup = alc883_medion_md2_setup,
10223 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010224 },
10225 [ALC888_LENOVO_MS7195_DIG] = {
10226 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10227 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10228 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10229 .dac_nids = alc883_dac_nids,
10230 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010231 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10232 .channel_mode = alc883_3ST_6ch_modes,
10233 .need_dac_fix = 1,
10234 .input_mux = &alc883_capture_source,
10235 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10236 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010237 },
10238 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010239 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010240 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10241 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10242 .dac_nids = alc883_dac_nids,
10243 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010244 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10245 .channel_mode = alc883_3ST_2ch_modes,
10246 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010247 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010248 .setup = alc883_haier_w66_setup,
10249 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010250 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010251 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010252 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010253 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010254 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10255 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010256 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10257 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010258 .need_dac_fix = 1,
10259 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010260 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010261 .setup = alc888_3st_hp_setup,
10262 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010263 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010264 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010265 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010266 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10267 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10268 .dac_nids = alc883_dac_nids,
10269 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010270 .dig_in_nid = ALC883_DIGIN_NID,
10271 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10272 .channel_mode = alc883_sixstack_modes,
10273 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010274 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010275 .setup = alc888_6st_dell_setup,
10276 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010277 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010278 [ALC883_MITAC] = {
10279 .mixers = { alc883_mitac_mixer },
10280 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10281 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10282 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010283 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10284 .channel_mode = alc883_3ST_2ch_modes,
10285 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010286 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010287 .setup = alc883_mitac_setup,
10288 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010289 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010290 [ALC883_FUJITSU_PI2515] = {
10291 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10292 .init_verbs = { alc883_init_verbs,
10293 alc883_2ch_fujitsu_pi2515_verbs},
10294 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10295 .dac_nids = alc883_dac_nids,
10296 .dig_out_nid = ALC883_DIGOUT_NID,
10297 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10298 .channel_mode = alc883_3ST_2ch_modes,
10299 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010300 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010301 .setup = alc883_2ch_fujitsu_pi2515_setup,
10302 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010303 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010304 [ALC888_FUJITSU_XA3530] = {
10305 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10306 .init_verbs = { alc883_init_verbs,
10307 alc888_fujitsu_xa3530_verbs },
10308 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10309 .dac_nids = alc883_dac_nids,
10310 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10311 .adc_nids = alc883_adc_nids_rev,
10312 .capsrc_nids = alc883_capsrc_nids_rev,
10313 .dig_out_nid = ALC883_DIGOUT_NID,
10314 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10315 .channel_mode = alc888_4ST_8ch_intel_modes,
10316 .num_mux_defs =
10317 ARRAY_SIZE(alc888_2_capture_sources),
10318 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010319 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010320 .setup = alc888_fujitsu_xa3530_setup,
10321 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010322 },
Kailang Yange2757d52008-08-26 13:17:46 +020010323 [ALC888_LENOVO_SKY] = {
10324 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10325 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10326 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10327 .dac_nids = alc883_dac_nids,
10328 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010329 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10330 .channel_mode = alc883_sixstack_modes,
10331 .need_dac_fix = 1,
10332 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010333 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010334 .setup = alc888_lenovo_sky_setup,
10335 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010336 },
10337 [ALC888_ASUS_M90V] = {
10338 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10339 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10340 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10341 .dac_nids = alc883_dac_nids,
10342 .dig_out_nid = ALC883_DIGOUT_NID,
10343 .dig_in_nid = ALC883_DIGIN_NID,
10344 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10345 .channel_mode = alc883_3ST_6ch_modes,
10346 .need_dac_fix = 1,
10347 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010348 .unsol_event = alc_sku_unsol_event,
10349 .setup = alc883_mode2_setup,
10350 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010351 },
10352 [ALC888_ASUS_EEE1601] = {
10353 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010354 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010355 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10356 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10357 .dac_nids = alc883_dac_nids,
10358 .dig_out_nid = ALC883_DIGOUT_NID,
10359 .dig_in_nid = ALC883_DIGIN_NID,
10360 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10361 .channel_mode = alc883_3ST_2ch_modes,
10362 .need_dac_fix = 1,
10363 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010364 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010365 .init_hook = alc883_eee1601_inithook,
10366 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010367 [ALC1200_ASUS_P5Q] = {
10368 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10369 .init_verbs = { alc883_init_verbs },
10370 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10371 .dac_nids = alc883_dac_nids,
10372 .dig_out_nid = ALC1200_DIGOUT_NID,
10373 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010374 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010375 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10376 .channel_mode = alc883_sixstack_modes,
10377 .input_mux = &alc883_capture_source,
10378 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010379 [ALC889A_MB31] = {
10380 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10381 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10382 alc880_gpio1_init_verbs },
10383 .adc_nids = alc883_adc_nids,
10384 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010385 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010386 .dac_nids = alc883_dac_nids,
10387 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10388 .channel_mode = alc889A_mb31_6ch_modes,
10389 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10390 .input_mux = &alc889A_mb31_capture_source,
10391 .dig_out_nid = ALC883_DIGOUT_NID,
10392 .unsol_event = alc889A_mb31_unsol_event,
10393 .init_hook = alc889A_mb31_automute,
10394 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010395 [ALC883_SONY_VAIO_TT] = {
10396 .mixers = { alc883_vaiott_mixer },
10397 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10398 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10399 .dac_nids = alc883_dac_nids,
10400 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10401 .channel_mode = alc883_3ST_2ch_modes,
10402 .input_mux = &alc883_capture_source,
10403 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010404 .setup = alc883_vaiott_setup,
10405 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010406 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010407};
10408
10409
10410/*
Takashi Iwai4953550a2009-06-30 15:28:30 +020010411 * Pin config fixes
10412 */
10413enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010414 PINFIX_ABIT_AW9D_MAX,
10415 PINFIX_PB_M5210,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010416};
10417
10418static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
10419 { 0x15, 0x01080104 }, /* side */
10420 { 0x16, 0x01011012 }, /* rear */
10421 { 0x17, 0x01016011 }, /* clfe */
10422 { }
10423};
10424
Takashi Iwai954a29c2010-07-30 10:55:44 +020010425static const struct hda_verb pb_m5210_verbs[] = {
10426 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10427 {}
10428};
10429
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010430static const struct alc_fixup alc882_fixups[] = {
10431 [PINFIX_ABIT_AW9D_MAX] = {
10432 .pins = alc882_abit_aw9d_pinfix
10433 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010434 [PINFIX_PB_M5210] = {
10435 .verbs = pb_m5210_verbs
10436 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010437};
10438
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010439static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010440 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010441 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
10442 {}
10443};
10444
10445/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010446 * BIOS auto configuration
10447 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010448static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10449 const struct auto_pin_cfg *cfg)
10450{
10451 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10452}
10453
Takashi Iwai4953550a2009-06-30 15:28:30 +020010454static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010455 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010456 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010457{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010458 int idx;
10459
Takashi Iwai489008c2010-04-07 09:06:00 +020010460 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010461 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010462
Takashi Iwai489008c2010-04-07 09:06:00 +020010463 if (dac == 0x25)
10464 idx = 4;
10465 else if (dac >= 0x02 && dac <= 0x05)
10466 idx = dac - 2;
10467 else
10468 return;
10469 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010470}
10471
Takashi Iwai4953550a2009-06-30 15:28:30 +020010472static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010473{
10474 struct alc_spec *spec = codec->spec;
10475 int i;
10476
10477 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010478 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010479 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010480 if (nid)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010481 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010482 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010483 }
10484}
10485
Takashi Iwai4953550a2009-06-30 15:28:30 +020010486static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010487{
10488 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010489 hda_nid_t pin, dac;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010490
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010491 pin = spec->autocfg.hp_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010492 if (pin) {
10493 dac = spec->multiout.hp_nid;
10494 if (!dac)
10495 dac = spec->multiout.dac_nids[0]; /* to front */
10496 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10497 }
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010498 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai489008c2010-04-07 09:06:00 +020010499 if (pin) {
10500 dac = spec->multiout.extra_out_nid[0];
10501 if (!dac)
10502 dac = spec->multiout.dac_nids[0]; /* to front */
10503 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10504 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010505}
10506
Takashi Iwai4953550a2009-06-30 15:28:30 +020010507static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010508{
10509 struct alc_spec *spec = codec->spec;
10510 int i;
10511
10512 for (i = 0; i < AUTO_PIN_LAST; i++) {
10513 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010514 if (!nid)
10515 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +020010516 alc_set_input_pin(codec, nid, i);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010517 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10518 snd_hda_codec_write(codec, nid, 0,
10519 AC_VERB_SET_AMP_GAIN_MUTE,
10520 AMP_OUT_MUTE);
10521 }
10522}
10523
10524static void alc882_auto_init_input_src(struct hda_codec *codec)
10525{
10526 struct alc_spec *spec = codec->spec;
10527 int c;
10528
10529 for (c = 0; c < spec->num_adc_nids; c++) {
10530 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10531 hda_nid_t nid = spec->capsrc_nids[c];
10532 unsigned int mux_idx;
10533 const struct hda_input_mux *imux;
10534 int conns, mute, idx, item;
10535
10536 conns = snd_hda_get_connections(codec, nid, conn_list,
10537 ARRAY_SIZE(conn_list));
10538 if (conns < 0)
10539 continue;
10540 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10541 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010542 if (!imux->num_items && mux_idx > 0)
10543 imux = &spec->input_mux[0];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010544 for (idx = 0; idx < conns; idx++) {
10545 /* if the current connection is the selected one,
10546 * unmute it as default - otherwise mute it
10547 */
10548 mute = AMP_IN_MUTE(idx);
10549 for (item = 0; item < imux->num_items; item++) {
10550 if (imux->items[item].index == idx) {
10551 if (spec->cur_mux[c] == item)
10552 mute = AMP_IN_UNMUTE(idx);
10553 break;
10554 }
10555 }
10556 /* check if we have a selector or mixer
10557 * we could check for the widget type instead, but
10558 * just check for Amp-In presence (in case of mixer
10559 * without amp-in there is something wrong, this
10560 * function shouldn't be used or capsrc nid is wrong)
10561 */
10562 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010563 snd_hda_codec_write(codec, nid, 0,
10564 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010565 mute);
10566 else if (mute != AMP_IN_MUTE(idx))
10567 snd_hda_codec_write(codec, nid, 0,
10568 AC_VERB_SET_CONNECT_SEL,
10569 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010570 }
10571 }
10572}
10573
Takashi Iwai4953550a2009-06-30 15:28:30 +020010574/* add mic boosts if needed */
10575static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010576{
10577 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010578 int err;
10579 hda_nid_t nid;
10580
10581 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
10582 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10583 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10584 "Mic Boost",
10585 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10586 if (err < 0)
10587 return err;
10588 }
10589 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
10590 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10591 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10592 "Front Mic Boost",
10593 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10594 if (err < 0)
10595 return err;
10596 }
10597 return 0;
10598}
10599
10600/* almost identical with ALC880 parser... */
10601static int alc882_parse_auto_config(struct hda_codec *codec)
10602{
10603 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010604 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010605 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010606
Takashi Iwai05f5f472009-08-25 13:10:18 +020010607 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10608 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010609 if (err < 0)
10610 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010611 if (!spec->autocfg.line_outs)
10612 return 0; /* can't find valid BIOS pin config */
10613
10614 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10615 if (err < 0)
10616 return err;
10617 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10618 if (err < 0)
10619 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010620 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10621 "Headphone");
10622 if (err < 0)
10623 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010624 err = alc880_auto_create_extra_out(spec,
10625 spec->autocfg.speaker_pins[0],
10626 "Speaker");
10627 if (err < 0)
10628 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010629 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10630 if (err < 0)
10631 return err;
10632
10633 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10634
Takashi Iwai757899a2010-07-30 10:48:14 +020010635 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010636
10637 if (spec->kctls.list)
10638 add_mixer(spec, spec->kctls.list);
10639
10640 add_verb(spec, alc883_auto_init_verbs);
10641 /* if ADC 0x07 is available, initialize it, too */
10642 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10643 add_verb(spec, alc882_adc1_init_verbs);
10644
10645 spec->num_mux_defs = 1;
10646 spec->input_mux = &spec->private_imux[0];
10647
Kailang Yang6227cdc2010-02-25 08:36:52 +010010648 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010649
10650 err = alc_auto_add_mic_boost(codec);
10651 if (err < 0)
10652 return err;
10653
Takashi Iwai776e1842007-08-29 15:07:11 +020010654 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010655}
10656
10657/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010658static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010659{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010660 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010661 alc882_auto_init_multi_out(codec);
10662 alc882_auto_init_hp_out(codec);
10663 alc882_auto_init_analog_input(codec);
10664 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010665 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010666 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010667 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010668}
10669
Takashi Iwai4953550a2009-06-30 15:28:30 +020010670static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010671{
10672 struct alc_spec *spec;
10673 int err, board_config;
10674
10675 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10676 if (spec == NULL)
10677 return -ENOMEM;
10678
10679 codec->spec = spec;
10680
Kailang Yangda00c242010-03-19 11:23:45 +010010681 alc_auto_parse_customize_define(codec);
10682
Takashi Iwai4953550a2009-06-30 15:28:30 +020010683 switch (codec->vendor_id) {
10684 case 0x10ec0882:
10685 case 0x10ec0885:
10686 break;
10687 default:
10688 /* ALC883 and variants */
10689 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10690 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010691 }
10692
Takashi Iwai4953550a2009-06-30 15:28:30 +020010693 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10694 alc882_models,
10695 alc882_cfg_tbl);
10696
10697 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10698 board_config = snd_hda_check_board_codec_sid_config(codec,
10699 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10700
10701 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010702 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020010703 codec->chip_name);
10704 board_config = ALC882_AUTO;
10705 }
10706
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010707 if (board_config == ALC882_AUTO)
10708 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010709
10710 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010711 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010712 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010713 if (err < 0) {
10714 alc_free(codec);
10715 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010716 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010717 printk(KERN_INFO
10718 "hda_codec: Cannot set up configuration "
10719 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020010720 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010721 }
10722 }
10723
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010724 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020010725 err = snd_hda_attach_beep_device(codec, 0x1);
10726 if (err < 0) {
10727 alc_free(codec);
10728 return err;
10729 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010730 }
10731
Takashi Iwai4953550a2009-06-30 15:28:30 +020010732 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010733 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010734
Takashi Iwai4953550a2009-06-30 15:28:30 +020010735 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10736 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10737 /* FIXME: setup DAC5 */
10738 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10739 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10740
10741 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10742 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10743
Takashi Iwai4953550a2009-06-30 15:28:30 +020010744 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010745 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010746 spec->num_adc_nids = 0;
10747 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010748 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010749 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010750 hda_nid_t items[16];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010751 hda_nid_t nid = alc882_adc_nids[i];
10752 unsigned int wcap = get_wcaps(codec, nid);
10753 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010754 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010755 if (wcap != AC_WID_AUD_IN)
10756 continue;
10757 spec->private_adc_nids[spec->num_adc_nids] = nid;
10758 err = snd_hda_get_connections(codec, nid, &cap, 1);
10759 if (err < 0)
10760 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010761 err = snd_hda_get_connections(codec, cap, items,
10762 ARRAY_SIZE(items));
10763 if (err < 0)
10764 continue;
10765 for (j = 0; j < imux->num_items; j++)
10766 if (imux->items[j].index >= err)
10767 break;
10768 if (j < imux->num_items)
10769 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010770 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10771 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010772 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010773 spec->adc_nids = spec->private_adc_nids;
10774 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010775 }
10776
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010777 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010010778
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010779 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010010780 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010781
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010782 if (board_config == ALC882_AUTO)
10783 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
10784
Takashi Iwai2134ea42008-01-10 16:53:55 +010010785 spec->vmaster_nid = 0x0c;
10786
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010787 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010788 if (board_config == ALC882_AUTO)
10789 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010790#ifdef CONFIG_SND_HDA_POWER_SAVE
10791 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010792 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010793#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010794
10795 return 0;
10796}
10797
Takashi Iwai4953550a2009-06-30 15:28:30 +020010798
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010799/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010800 * ALC262 support
10801 */
10802
10803#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10804#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10805
10806#define alc262_dac_nids alc260_dac_nids
10807#define alc262_adc_nids alc882_adc_nids
10808#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010809#define alc262_capsrc_nids alc882_capsrc_nids
10810#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010811
10812#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010813#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010814
Kailang Yang4e555fe2008-08-26 13:05:55 +020010815static hda_nid_t alc262_dmic_adc_nids[1] = {
10816 /* ADC0 */
10817 0x09
10818};
10819
10820static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10821
Kailang Yangdf694da2005-12-05 19:42:22 +010010822static struct snd_kcontrol_new alc262_base_mixer[] = {
10823 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10824 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10825 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10826 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10827 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10828 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10829 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10830 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010831 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010832 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10833 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010834 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010835 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10836 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10837 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10838 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010839 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010840};
10841
Takashi Iwaice875f02008-01-28 18:17:43 +010010842/* update HP, line and mono-out pins according to the master switch */
10843static void alc262_hp_master_update(struct hda_codec *codec)
10844{
10845 struct alc_spec *spec = codec->spec;
10846 int val = spec->master_sw;
10847
10848 /* HP & line-out */
10849 snd_hda_codec_write_cache(codec, 0x1b, 0,
10850 AC_VERB_SET_PIN_WIDGET_CONTROL,
10851 val ? PIN_HP : 0);
10852 snd_hda_codec_write_cache(codec, 0x15, 0,
10853 AC_VERB_SET_PIN_WIDGET_CONTROL,
10854 val ? PIN_HP : 0);
10855 /* mono (speaker) depending on the HP jack sense */
10856 val = val && !spec->jack_present;
10857 snd_hda_codec_write_cache(codec, 0x16, 0,
10858 AC_VERB_SET_PIN_WIDGET_CONTROL,
10859 val ? PIN_OUT : 0);
10860}
10861
10862static void alc262_hp_bpc_automute(struct hda_codec *codec)
10863{
10864 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010865
10866 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010867 alc262_hp_master_update(codec);
10868}
10869
10870static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10871{
10872 if ((res >> 26) != ALC880_HP_EVENT)
10873 return;
10874 alc262_hp_bpc_automute(codec);
10875}
10876
10877static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10878{
10879 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010880
10881 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010882 alc262_hp_master_update(codec);
10883}
10884
10885static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10886 unsigned int res)
10887{
10888 if ((res >> 26) != ALC880_HP_EVENT)
10889 return;
10890 alc262_hp_wildwest_automute(codec);
10891}
10892
Takashi Iwaib72519b2009-05-08 14:31:55 +020010893#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010894
10895static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10896 struct snd_ctl_elem_value *ucontrol)
10897{
10898 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10899 struct alc_spec *spec = codec->spec;
10900 int val = !!*ucontrol->value.integer.value;
10901
10902 if (val == spec->master_sw)
10903 return 0;
10904 spec->master_sw = val;
10905 alc262_hp_master_update(codec);
10906 return 1;
10907}
10908
Takashi Iwaib72519b2009-05-08 14:31:55 +020010909#define ALC262_HP_MASTER_SWITCH \
10910 { \
10911 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10912 .name = "Master Playback Switch", \
10913 .info = snd_ctl_boolean_mono_info, \
10914 .get = alc262_hp_master_sw_get, \
10915 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010916 }, \
10917 { \
10918 .iface = NID_MAPPING, \
10919 .name = "Master Playback Switch", \
10920 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010921 }
10922
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010923
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010924static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010925 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010926 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10927 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010929 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10930 HDA_OUTPUT),
10931 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10932 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010933 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10934 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010935 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010936 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10937 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010938 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010939 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10940 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10941 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10942 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010943 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10944 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10945 { } /* end */
10946};
10947
Kailang Yangcd7509a2007-01-26 18:33:17 +010010948static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010949 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010950 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10951 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10952 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10953 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010954 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10955 HDA_OUTPUT),
10956 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10957 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010958 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10959 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010960 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010961 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10962 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10963 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10964 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010965 { } /* end */
10966};
10967
10968static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10969 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10970 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010971 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010972 { } /* end */
10973};
10974
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010975/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010976static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010977{
10978 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010979
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010980 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010010981 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010982}
10983
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010984static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010985 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10986 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010987 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10988 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10989 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10990 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10991 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10992 { } /* end */
10993};
10994
10995static struct hda_verb alc262_hp_t5735_verbs[] = {
10996 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10997 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10998
10999 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11000 { }
11001};
11002
Kailang Yang8c427222008-01-10 13:03:59 +010011003static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011004 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11005 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011006 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11007 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011008 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11009 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11010 { } /* end */
11011};
11012
11013static struct hda_verb alc262_hp_rp5700_verbs[] = {
11014 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11015 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11016 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11017 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11018 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11019 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11020 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11021 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11022 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11023 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11024 {}
11025};
11026
11027static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11028 .num_items = 1,
11029 .items = {
11030 { "Line", 0x1 },
11031 },
11032};
11033
Takashi Iwai42171c12009-05-08 14:11:43 +020011034/* bind hp and internal speaker mute (with plug check) as master switch */
11035static void alc262_hippo_master_update(struct hda_codec *codec)
11036{
11037 struct alc_spec *spec = codec->spec;
11038 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11039 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11040 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11041 unsigned int mute;
11042
11043 /* HP */
11044 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11045 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11046 HDA_AMP_MUTE, mute);
11047 /* mute internal speaker per jack sense */
11048 if (spec->jack_present)
11049 mute = HDA_AMP_MUTE;
11050 if (line_nid)
11051 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11052 HDA_AMP_MUTE, mute);
11053 if (speaker_nid && speaker_nid != line_nid)
11054 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11055 HDA_AMP_MUTE, mute);
11056}
11057
11058#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11059
11060static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11061 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011062{
11063 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011064 struct alc_spec *spec = codec->spec;
11065 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011066
Takashi Iwai42171c12009-05-08 14:11:43 +020011067 if (val == spec->master_sw)
11068 return 0;
11069 spec->master_sw = val;
11070 alc262_hippo_master_update(codec);
11071 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011072}
Takashi Iwai5b319542007-07-26 11:49:22 +020011073
Takashi Iwai42171c12009-05-08 14:11:43 +020011074#define ALC262_HIPPO_MASTER_SWITCH \
11075 { \
11076 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11077 .name = "Master Playback Switch", \
11078 .info = snd_ctl_boolean_mono_info, \
11079 .get = alc262_hippo_master_sw_get, \
11080 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011081 }, \
11082 { \
11083 .iface = NID_MAPPING, \
11084 .name = "Master Playback Switch", \
11085 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11086 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011087 }
11088
11089static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11090 ALC262_HIPPO_MASTER_SWITCH,
11091 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11092 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11093 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11094 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11095 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11097 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11098 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11099 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11100 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11101 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11102 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11103 { } /* end */
11104};
11105
11106static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11107 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11108 ALC262_HIPPO_MASTER_SWITCH,
11109 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11110 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11111 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11112 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11113 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11114 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11115 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11116 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11117 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11118 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11119 { } /* end */
11120};
11121
11122/* mute/unmute internal speaker according to the hp jack and mute state */
11123static void alc262_hippo_automute(struct hda_codec *codec)
11124{
11125 struct alc_spec *spec = codec->spec;
11126 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011127
Wu Fengguang864f92b2009-11-18 12:38:02 +080011128 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011129 alc262_hippo_master_update(codec);
11130}
11131
11132static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11133{
11134 if ((res >> 26) != ALC880_HP_EVENT)
11135 return;
11136 alc262_hippo_automute(codec);
11137}
11138
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011139static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011140{
11141 struct alc_spec *spec = codec->spec;
11142
11143 spec->autocfg.hp_pins[0] = 0x15;
11144 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011145}
11146
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011147static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011148{
11149 struct alc_spec *spec = codec->spec;
11150
11151 spec->autocfg.hp_pins[0] = 0x1b;
11152 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011153}
11154
11155
Kailang Yang272a5272007-05-14 11:00:38 +020011156static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011157 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011158 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011159 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11160 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11161 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11162 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11163 { } /* end */
11164};
11165
Kailang Yang83c34212007-07-05 11:43:05 +020011166static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011167 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11168 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011169 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11170 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11171 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11172 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11173 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11174 { } /* end */
11175};
Kailang Yang272a5272007-05-14 11:00:38 +020011176
Tony Vroonba340e82009-02-02 19:01:30 +000011177static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11178 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11179 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11180 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11181 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11182 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11183 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11184 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11185 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11186 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11187 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11188 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11189 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11190 { } /* end */
11191};
11192
11193static struct hda_verb alc262_tyan_verbs[] = {
11194 /* Headphone automute */
11195 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11196 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11197 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11198
11199 /* P11 AUX_IN, white 4-pin connector */
11200 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11201 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11202 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11203 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11204
11205 {}
11206};
11207
11208/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011209static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011210{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011211 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011212
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011213 spec->autocfg.hp_pins[0] = 0x1b;
11214 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011215}
11216
Tony Vroonba340e82009-02-02 19:01:30 +000011217
Kailang Yangdf694da2005-12-05 19:42:22 +010011218#define alc262_capture_mixer alc882_capture_mixer
11219#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11220
11221/*
11222 * generic initialization of ADC, input mixers and output mixers
11223 */
11224static struct hda_verb alc262_init_verbs[] = {
11225 /*
11226 * Unmute ADC0-2 and set the default input to mic-in
11227 */
11228 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11229 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11230 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11231 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11232 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11233 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11234
Takashi Iwaicb53c622007-08-10 17:21:45 +020011235 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011236 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011237 * Note: PASD motherboards uses the Line In 2 as the input for
11238 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011239 */
11240 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011241 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11242 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11243 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11244 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11245 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011246
11247 /*
11248 * Set up output mixers (0x0c - 0x0e)
11249 */
11250 /* set vol=0 to output mixers */
11251 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11252 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11253 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11254 /* set up input amps for analog loopback */
11255 /* Amp Indices: DAC = 0, mixer = 1 */
11256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11257 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11258 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11259 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11260 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11261 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11262
11263 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11264 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11265 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11266 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11267 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11268 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11269
11270 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11271 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11272 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11273 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11274 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011275
Kailang Yangdf694da2005-12-05 19:42:22 +010011276 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11277 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011278
Kailang Yangdf694da2005-12-05 19:42:22 +010011279 /* FIXME: use matrix-type input source selection */
11280 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11281 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11282 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11283 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11284 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11285 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11286 /* Input mixer2 */
11287 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11288 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11289 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11290 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11291 /* Input mixer3 */
11292 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11293 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11294 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011295 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011296
11297 { }
11298};
11299
Kailang Yang4e555fe2008-08-26 13:05:55 +020011300static struct hda_verb alc262_eapd_verbs[] = {
11301 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11302 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11303 { }
11304};
11305
Kailang Yangccc656c2006-10-17 12:32:26 +020011306static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11307 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11308 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11309 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11310
11311 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11312 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11313 {}
11314};
11315
Kailang Yang272a5272007-05-14 11:00:38 +020011316static struct hda_verb alc262_sony_unsol_verbs[] = {
11317 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11318 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11319 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11320
11321 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11322 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011323 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011324};
11325
Kailang Yang4e555fe2008-08-26 13:05:55 +020011326static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11327 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11328 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11329 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11330 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11331 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011332 { } /* end */
11333};
11334
11335static struct hda_verb alc262_toshiba_s06_verbs[] = {
11336 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11337 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11338 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11339 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11340 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11341 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11342 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11343 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11344 {}
11345};
11346
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011347static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011348{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011349 struct alc_spec *spec = codec->spec;
11350
11351 spec->autocfg.hp_pins[0] = 0x15;
11352 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011353 spec->ext_mic.pin = 0x18;
11354 spec->ext_mic.mux_idx = 0;
11355 spec->int_mic.pin = 0x12;
11356 spec->int_mic.mux_idx = 9;
11357 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011358}
11359
Takashi Iwai834be882006-03-01 14:16:17 +010011360/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011361 * nec model
11362 * 0x15 = headphone
11363 * 0x16 = internal speaker
11364 * 0x18 = external mic
11365 */
11366
11367static struct snd_kcontrol_new alc262_nec_mixer[] = {
11368 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11369 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11370
11371 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11372 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11373 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11374
11375 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11376 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11377 { } /* end */
11378};
11379
11380static struct hda_verb alc262_nec_verbs[] = {
11381 /* Unmute Speaker */
11382 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11383
11384 /* Headphone */
11385 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11386 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11387
11388 /* External mic to headphone */
11389 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11390 /* External mic to speaker */
11391 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11392 {}
11393};
11394
11395/*
Takashi Iwai834be882006-03-01 14:16:17 +010011396 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011397 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11398 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011399 */
11400
11401#define ALC_HP_EVENT 0x37
11402
11403static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11404 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11405 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011406 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11407 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011408 {}
11409};
11410
Jiang zhe0e31daf2008-03-20 12:12:39 +010011411static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11412 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11413 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11414 {}
11415};
11416
Daniel T Chene2595322009-12-19 18:19:02 -050011417static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11418 /* Front Mic pin: input vref at 50% */
11419 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11420 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11421 {}
11422};
11423
Takashi Iwai834be882006-03-01 14:16:17 +010011424static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011425 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011426 .items = {
11427 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011428 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011429 { "CD", 0x4 },
11430 },
11431};
11432
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011433static struct hda_input_mux alc262_HP_capture_source = {
11434 .num_items = 5,
11435 .items = {
11436 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011437 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011438 { "Line", 0x2 },
11439 { "CD", 0x4 },
11440 { "AUX IN", 0x6 },
11441 },
11442};
11443
zhejiangaccbe492007-08-31 12:36:05 +020011444static struct hda_input_mux alc262_HP_D7000_capture_source = {
11445 .num_items = 4,
11446 .items = {
11447 { "Mic", 0x0 },
11448 { "Front Mic", 0x2 },
11449 { "Line", 0x1 },
11450 { "CD", 0x4 },
11451 },
11452};
11453
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011454/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011455static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11456{
11457 struct alc_spec *spec = codec->spec;
11458 unsigned int mute;
11459
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011460 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011461 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11462 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011463 spec->sense_updated = 1;
11464 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011465 /* unmute internal speaker only if both HPs are unplugged and
11466 * master switch is on
11467 */
11468 if (spec->jack_present)
11469 mute = HDA_AMP_MUTE;
11470 else
Takashi Iwai834be882006-03-01 14:16:17 +010011471 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011472 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11473 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011474}
11475
11476/* unsolicited event for HP jack sensing */
11477static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11478 unsigned int res)
11479{
11480 if ((res >> 26) != ALC_HP_EVENT)
11481 return;
11482 alc262_fujitsu_automute(codec, 1);
11483}
11484
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011485static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11486{
11487 alc262_fujitsu_automute(codec, 1);
11488}
11489
Takashi Iwai834be882006-03-01 14:16:17 +010011490/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011491static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11492 .ops = &snd_hda_bind_vol,
11493 .values = {
11494 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11495 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11496 0
11497 },
11498};
Takashi Iwai834be882006-03-01 14:16:17 +010011499
Jiang zhe0e31daf2008-03-20 12:12:39 +010011500/* mute/unmute internal speaker according to the hp jack and mute state */
11501static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11502{
11503 struct alc_spec *spec = codec->spec;
11504 unsigned int mute;
11505
11506 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011507 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011508 spec->sense_updated = 1;
11509 }
11510 if (spec->jack_present) {
11511 /* mute internal speaker */
11512 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11513 HDA_AMP_MUTE, HDA_AMP_MUTE);
11514 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11515 HDA_AMP_MUTE, HDA_AMP_MUTE);
11516 } else {
11517 /* unmute internal speaker if necessary */
11518 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11519 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11520 HDA_AMP_MUTE, mute);
11521 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11522 HDA_AMP_MUTE, mute);
11523 }
11524}
11525
11526/* unsolicited event for HP jack sensing */
11527static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11528 unsigned int res)
11529{
11530 if ((res >> 26) != ALC_HP_EVENT)
11531 return;
11532 alc262_lenovo_3000_automute(codec, 1);
11533}
11534
Takashi Iwai8de56b72009-07-24 16:51:47 +020011535static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11536 int dir, int idx, long *valp)
11537{
11538 int i, change = 0;
11539
11540 for (i = 0; i < 2; i++, valp++)
11541 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11542 HDA_AMP_MUTE,
11543 *valp ? 0 : HDA_AMP_MUTE);
11544 return change;
11545}
11546
Takashi Iwai834be882006-03-01 14:16:17 +010011547/* bind hp and internal speaker mute (with plug check) */
11548static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11549 struct snd_ctl_elem_value *ucontrol)
11550{
11551 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11552 long *valp = ucontrol->value.integer.value;
11553 int change;
11554
Takashi Iwai8de56b72009-07-24 16:51:47 +020011555 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11556 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011557 if (change)
11558 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011559 return change;
11560}
11561
11562static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011563 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011564 {
11565 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11566 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011567 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011568 .info = snd_hda_mixer_amp_switch_info,
11569 .get = snd_hda_mixer_amp_switch_get,
11570 .put = alc262_fujitsu_master_sw_put,
11571 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11572 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011573 {
11574 .iface = NID_MAPPING,
11575 .name = "Master Playback Switch",
11576 .private_value = 0x1b,
11577 },
Takashi Iwai834be882006-03-01 14:16:17 +010011578 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11579 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11580 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11581 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11582 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011583 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11584 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11585 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011586 { } /* end */
11587};
11588
Jiang zhe0e31daf2008-03-20 12:12:39 +010011589/* bind hp and internal speaker mute (with plug check) */
11590static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11591 struct snd_ctl_elem_value *ucontrol)
11592{
11593 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11594 long *valp = ucontrol->value.integer.value;
11595 int change;
11596
Takashi Iwai8de56b72009-07-24 16:51:47 +020011597 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011598 if (change)
11599 alc262_lenovo_3000_automute(codec, 0);
11600 return change;
11601}
11602
11603static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11604 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11605 {
11606 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11607 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011608 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011609 .info = snd_hda_mixer_amp_switch_info,
11610 .get = snd_hda_mixer_amp_switch_get,
11611 .put = alc262_lenovo_3000_master_sw_put,
11612 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11613 },
11614 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11615 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11616 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11617 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11618 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11619 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11620 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11621 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11622 { } /* end */
11623};
11624
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011625static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11626 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011627 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011628 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11629 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11630 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11631 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11632 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11633 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11634 { } /* end */
11635};
11636
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011637/* additional init verbs for Benq laptops */
11638static struct hda_verb alc262_EAPD_verbs[] = {
11639 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11640 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11641 {}
11642};
11643
Kailang Yang83c34212007-07-05 11:43:05 +020011644static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11645 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11646 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11647
11648 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11649 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11650 {}
11651};
11652
Tobin Davisf651b502007-10-26 12:40:47 +020011653/* Samsung Q1 Ultra Vista model setup */
11654static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011655 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11656 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011657 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11658 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11659 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011660 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011661 { } /* end */
11662};
11663
11664static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011665 /* output mixer */
11666 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11667 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11668 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11669 /* speaker */
11670 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11671 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11672 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11673 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11674 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011675 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011676 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11677 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11678 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11679 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11680 /* internal mic */
11681 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11682 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11683 /* ADC, choose mic */
11684 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11685 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11686 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11687 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11688 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11689 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11690 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11691 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11692 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11693 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011694 {}
11695};
11696
Tobin Davisf651b502007-10-26 12:40:47 +020011697/* mute/unmute internal speaker according to the hp jack and mute state */
11698static void alc262_ultra_automute(struct hda_codec *codec)
11699{
11700 struct alc_spec *spec = codec->spec;
11701 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011702
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011703 mute = 0;
11704 /* auto-mute only when HP is used as HP */
11705 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011706 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011707 if (spec->jack_present)
11708 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011709 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011710 /* mute/unmute internal speaker */
11711 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11712 HDA_AMP_MUTE, mute);
11713 /* mute/unmute HP */
11714 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11715 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011716}
11717
11718/* unsolicited event for HP jack sensing */
11719static void alc262_ultra_unsol_event(struct hda_codec *codec,
11720 unsigned int res)
11721{
11722 if ((res >> 26) != ALC880_HP_EVENT)
11723 return;
11724 alc262_ultra_automute(codec);
11725}
11726
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011727static struct hda_input_mux alc262_ultra_capture_source = {
11728 .num_items = 2,
11729 .items = {
11730 { "Mic", 0x1 },
11731 { "Headphone", 0x7 },
11732 },
11733};
11734
11735static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11736 struct snd_ctl_elem_value *ucontrol)
11737{
11738 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11739 struct alc_spec *spec = codec->spec;
11740 int ret;
11741
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011742 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011743 if (!ret)
11744 return 0;
11745 /* reprogram the HP pin as mic or HP according to the input source */
11746 snd_hda_codec_write_cache(codec, 0x15, 0,
11747 AC_VERB_SET_PIN_WIDGET_CONTROL,
11748 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11749 alc262_ultra_automute(codec); /* mute/unmute HP */
11750 return ret;
11751}
11752
11753static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11754 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11755 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11756 {
11757 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11758 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011759 .info = alc_mux_enum_info,
11760 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011761 .put = alc262_ultra_mux_enum_put,
11762 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011763 {
11764 .iface = NID_MAPPING,
11765 .name = "Capture Source",
11766 .private_value = 0x15,
11767 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011768 { } /* end */
11769};
11770
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011771/* We use two mixers depending on the output pin; 0x16 is a mono output
11772 * and thus it's bound with a different mixer.
11773 * This function returns which mixer amp should be used.
11774 */
11775static int alc262_check_volbit(hda_nid_t nid)
11776{
11777 if (!nid)
11778 return 0;
11779 else if (nid == 0x16)
11780 return 2;
11781 else
11782 return 1;
11783}
11784
11785static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11786 const char *pfx, int *vbits)
11787{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011788 unsigned long val;
11789 int vbit;
11790
11791 vbit = alc262_check_volbit(nid);
11792 if (!vbit)
11793 return 0;
11794 if (*vbits & vbit) /* a volume control for this mixer already there */
11795 return 0;
11796 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011797 if (vbit == 2)
11798 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11799 else
11800 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011801 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011802}
11803
11804static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11805 const char *pfx)
11806{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011807 unsigned long val;
11808
11809 if (!nid)
11810 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011811 if (nid == 0x16)
11812 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11813 else
11814 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011815 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011816}
11817
Kailang Yangdf694da2005-12-05 19:42:22 +010011818/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011819static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11820 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011821{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011822 const char *pfx;
11823 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011824 int err;
11825
11826 spec->multiout.num_dacs = 1; /* only use one dac */
11827 spec->multiout.dac_nids = spec->private_dac_nids;
11828 spec->multiout.dac_nids[0] = 2;
11829
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011830 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11831 pfx = "Master";
11832 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11833 pfx = "Speaker";
11834 else
11835 pfx = "Front";
11836 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11837 if (err < 0)
11838 return err;
11839 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11840 if (err < 0)
11841 return err;
11842 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11843 if (err < 0)
11844 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011845
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011846 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11847 alc262_check_volbit(cfg->speaker_pins[0]) |
11848 alc262_check_volbit(cfg->hp_pins[0]);
11849 if (vbits == 1 || vbits == 2)
11850 pfx = "Master"; /* only one mixer is used */
11851 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11852 pfx = "Speaker";
11853 else
11854 pfx = "Front";
11855 vbits = 0;
11856 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11857 if (err < 0)
11858 return err;
11859 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11860 &vbits);
11861 if (err < 0)
11862 return err;
11863 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11864 &vbits);
11865 if (err < 0)
11866 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011867 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011868}
11869
Takashi Iwai05f5f472009-08-25 13:10:18 +020011870#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010011871 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011872
11873/*
11874 * generic initialization of ADC, input mixers and output mixers
11875 */
11876static struct hda_verb alc262_volume_init_verbs[] = {
11877 /*
11878 * Unmute ADC0-2 and set the default input to mic-in
11879 */
11880 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11881 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11882 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11883 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11884 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11885 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11886
Takashi Iwaicb53c622007-08-10 17:21:45 +020011887 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011888 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011889 * Note: PASD motherboards uses the Line In 2 as the input for
11890 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011891 */
11892 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011893 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11894 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11895 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11896 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11897 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011898
11899 /*
11900 * Set up output mixers (0x0c - 0x0f)
11901 */
11902 /* set vol=0 to output mixers */
11903 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11904 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11905 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011906
Kailang Yangdf694da2005-12-05 19:42:22 +010011907 /* set up input amps for analog loopback */
11908 /* Amp Indices: DAC = 0, mixer = 1 */
11909 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11910 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11911 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11912 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11913 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11914 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11915
11916 /* FIXME: use matrix-type input source selection */
11917 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11918 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11919 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11920 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11921 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11922 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11923 /* Input mixer2 */
11924 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11925 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11926 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11927 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11928 /* Input mixer3 */
11929 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11930 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11931 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11932 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11933
11934 { }
11935};
11936
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011937static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11938 /*
11939 * Unmute ADC0-2 and set the default input to mic-in
11940 */
11941 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11942 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11943 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11944 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11945 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11946 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11947
Takashi Iwaicb53c622007-08-10 17:21:45 +020011948 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011949 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011950 * Note: PASD motherboards uses the Line In 2 as the input for
11951 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011952 */
11953 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011954 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11955 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11956 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11957 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11958 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11959 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11960 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011961
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011962 /*
11963 * Set up output mixers (0x0c - 0x0e)
11964 */
11965 /* set vol=0 to output mixers */
11966 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11967 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11968 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11969
11970 /* set up input amps for analog loopback */
11971 /* Amp Indices: DAC = 0, mixer = 1 */
11972 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11973 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11974 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11975 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11976 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11977 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11978
Takashi Iwaice875f02008-01-28 18:17:43 +010011979 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011980 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11981 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11982
11983 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11984 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11985
11986 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11987 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11988
11989 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11990 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11991 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11992 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11993 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11994
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011995 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011996 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11997 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011998 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011999 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12000 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12001
12002
12003 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012004 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12005 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012006 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012007 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12008 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12009 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12010 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12011 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12012 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12013 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12014 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012015 /* Input mixer2 */
12016 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012017 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12018 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12019 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12020 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12021 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12022 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12023 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12024 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012025 /* Input mixer3 */
12026 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012027 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12028 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12029 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12030 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12031 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12033 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12034 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012035
Takashi Iwaice875f02008-01-28 18:17:43 +010012036 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12037
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012038 { }
12039};
12040
Kailang Yangcd7509a2007-01-26 18:33:17 +010012041static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12042 /*
12043 * Unmute ADC0-2 and set the default input to mic-in
12044 */
12045 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12046 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12047 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12048 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12049 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12050 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12051
Takashi Iwaicb53c622007-08-10 17:21:45 +020012052 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012053 * mixer widget
12054 * Note: PASD motherboards uses the Line In 2 as the input for front
12055 * panel mic (mic 2)
12056 */
12057 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012058 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12059 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12060 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12061 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12062 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12063 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12064 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12065 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012066 /*
12067 * Set up output mixers (0x0c - 0x0e)
12068 */
12069 /* set vol=0 to output mixers */
12070 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12071 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12072 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12073
12074 /* set up input amps for analog loopback */
12075 /* Amp Indices: DAC = 0, mixer = 1 */
12076 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12077 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12078 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12079 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12080 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12081 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12082
12083
12084 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12085 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12086 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12087 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12088 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12089 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12090 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12091
12092 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12093 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12094
12095 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12096 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12097
12098 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12099 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12100 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12101 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12102 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12103 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12104
12105 /* FIXME: use matrix-type input source selection */
12106 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12107 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12108 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12109 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12110 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12111 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12112 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12113 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12114 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12115 /* Input mixer2 */
12116 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12117 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12118 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12119 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12120 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12121 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12122 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12123 /* Input mixer3 */
12124 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12125 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12126 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12127 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12128 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12129 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12130 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12131
Takashi Iwaice875f02008-01-28 18:17:43 +010012132 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12133
Kailang Yangcd7509a2007-01-26 18:33:17 +010012134 { }
12135};
12136
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012137static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12138
12139 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12140 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12141 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12142
12143 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12144 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12145 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12146 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12147
12148 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12149 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12150 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12151 {}
12152};
12153
12154
Takashi Iwaicb53c622007-08-10 17:21:45 +020012155#ifdef CONFIG_SND_HDA_POWER_SAVE
12156#define alc262_loopbacks alc880_loopbacks
12157#endif
12158
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012159/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012160#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12161#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12162#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12163#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12164
12165/*
12166 * BIOS auto configuration
12167 */
12168static int alc262_parse_auto_config(struct hda_codec *codec)
12169{
12170 struct alc_spec *spec = codec->spec;
12171 int err;
12172 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12173
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012174 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12175 alc262_ignore);
12176 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012177 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012178 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012179 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012180 spec->multiout.max_channels = 2;
12181 spec->no_analog = 1;
12182 goto dig_only;
12183 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012184 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012185 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012186 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12187 if (err < 0)
12188 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012189 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012190 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012191 return err;
12192
12193 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12194
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012195 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012196 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012197
Takashi Iwai603c4012008-07-30 15:01:44 +020012198 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012199 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012200
Takashi Iwaid88897e2008-10-31 15:01:37 +010012201 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012202 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012203 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012204
Takashi Iwai776e1842007-08-29 15:07:11 +020012205 err = alc_auto_add_mic_boost(codec);
12206 if (err < 0)
12207 return err;
12208
Kailang Yang6227cdc2010-02-25 08:36:52 +010012209 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012210
Kailang Yangdf694da2005-12-05 19:42:22 +010012211 return 1;
12212}
12213
12214#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12215#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12216#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012217#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012218
12219
12220/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012221static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012222{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012223 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012224 alc262_auto_init_multi_out(codec);
12225 alc262_auto_init_hp_out(codec);
12226 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012227 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012228 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012229 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012230 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012231}
12232
12233/*
12234 * configuration and preset
12235 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012236static const char *alc262_models[ALC262_MODEL_LAST] = {
12237 [ALC262_BASIC] = "basic",
12238 [ALC262_HIPPO] = "hippo",
12239 [ALC262_HIPPO_1] = "hippo_1",
12240 [ALC262_FUJITSU] = "fujitsu",
12241 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012242 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012243 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012244 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012245 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012246 [ALC262_BENQ_T31] = "benq-t31",
12247 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012248 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012249 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012250 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012251 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012252 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012253 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012254 [ALC262_AUTO] = "auto",
12255};
12256
12257static struct snd_pci_quirk alc262_cfg_tbl[] = {
12258 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012259 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012260 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12261 ALC262_HP_BPC),
12262 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12263 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012264 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12265 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012266 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012267 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012268 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012269 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012270 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012271 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012272 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012273 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012274 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12275 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12276 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012277 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12278 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012279 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012280 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012281 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012282 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012283 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012284 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012285 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012286 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012287#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012288 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12289 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012290#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012291 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012292 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012293 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012294 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012295 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012296 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012297 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12298 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012299 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012300 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012301 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012302 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012303 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012304 {}
12305};
12306
12307static struct alc_config_preset alc262_presets[] = {
12308 [ALC262_BASIC] = {
12309 .mixers = { alc262_base_mixer },
12310 .init_verbs = { alc262_init_verbs },
12311 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12312 .dac_nids = alc262_dac_nids,
12313 .hp_nid = 0x03,
12314 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12315 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012316 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012317 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012318 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012319 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012320 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012321 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12322 .dac_nids = alc262_dac_nids,
12323 .hp_nid = 0x03,
12324 .dig_out_nid = ALC262_DIGOUT_NID,
12325 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12326 .channel_mode = alc262_modes,
12327 .input_mux = &alc262_capture_source,
12328 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012329 .setup = alc262_hippo_setup,
12330 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012331 },
12332 [ALC262_HIPPO_1] = {
12333 .mixers = { alc262_hippo1_mixer },
12334 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12335 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12336 .dac_nids = alc262_dac_nids,
12337 .hp_nid = 0x02,
12338 .dig_out_nid = ALC262_DIGOUT_NID,
12339 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12340 .channel_mode = alc262_modes,
12341 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012342 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012343 .setup = alc262_hippo1_setup,
12344 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012345 },
Takashi Iwai834be882006-03-01 14:16:17 +010012346 [ALC262_FUJITSU] = {
12347 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012348 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12349 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012350 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12351 .dac_nids = alc262_dac_nids,
12352 .hp_nid = 0x03,
12353 .dig_out_nid = ALC262_DIGOUT_NID,
12354 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12355 .channel_mode = alc262_modes,
12356 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012357 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012358 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012359 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012360 [ALC262_HP_BPC] = {
12361 .mixers = { alc262_HP_BPC_mixer },
12362 .init_verbs = { alc262_HP_BPC_init_verbs },
12363 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12364 .dac_nids = alc262_dac_nids,
12365 .hp_nid = 0x03,
12366 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12367 .channel_mode = alc262_modes,
12368 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012369 .unsol_event = alc262_hp_bpc_unsol_event,
12370 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012371 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012372 [ALC262_HP_BPC_D7000_WF] = {
12373 .mixers = { alc262_HP_BPC_WildWest_mixer },
12374 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12375 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12376 .dac_nids = alc262_dac_nids,
12377 .hp_nid = 0x03,
12378 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12379 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012380 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012381 .unsol_event = alc262_hp_wildwest_unsol_event,
12382 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012383 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012384 [ALC262_HP_BPC_D7000_WL] = {
12385 .mixers = { alc262_HP_BPC_WildWest_mixer,
12386 alc262_HP_BPC_WildWest_option_mixer },
12387 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12388 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12389 .dac_nids = alc262_dac_nids,
12390 .hp_nid = 0x03,
12391 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12392 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012393 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012394 .unsol_event = alc262_hp_wildwest_unsol_event,
12395 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012396 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012397 [ALC262_HP_TC_T5735] = {
12398 .mixers = { alc262_hp_t5735_mixer },
12399 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12400 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12401 .dac_nids = alc262_dac_nids,
12402 .hp_nid = 0x03,
12403 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12404 .channel_mode = alc262_modes,
12405 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012406 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012407 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012408 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012409 },
12410 [ALC262_HP_RP5700] = {
12411 .mixers = { alc262_hp_rp5700_mixer },
12412 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12413 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12414 .dac_nids = alc262_dac_nids,
12415 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12416 .channel_mode = alc262_modes,
12417 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012418 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012419 [ALC262_BENQ_ED8] = {
12420 .mixers = { alc262_base_mixer },
12421 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12422 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12423 .dac_nids = alc262_dac_nids,
12424 .hp_nid = 0x03,
12425 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12426 .channel_mode = alc262_modes,
12427 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012428 },
Kailang Yang272a5272007-05-14 11:00:38 +020012429 [ALC262_SONY_ASSAMD] = {
12430 .mixers = { alc262_sony_mixer },
12431 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12432 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12433 .dac_nids = alc262_dac_nids,
12434 .hp_nid = 0x02,
12435 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12436 .channel_mode = alc262_modes,
12437 .input_mux = &alc262_capture_source,
12438 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012439 .setup = alc262_hippo_setup,
12440 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012441 },
12442 [ALC262_BENQ_T31] = {
12443 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012444 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12445 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012446 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12447 .dac_nids = alc262_dac_nids,
12448 .hp_nid = 0x03,
12449 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12450 .channel_mode = alc262_modes,
12451 .input_mux = &alc262_capture_source,
12452 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012453 .setup = alc262_hippo_setup,
12454 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012455 },
Tobin Davisf651b502007-10-26 12:40:47 +020012456 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012457 .mixers = { alc262_ultra_mixer },
12458 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012459 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012460 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12461 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012462 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12463 .channel_mode = alc262_modes,
12464 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012465 .adc_nids = alc262_adc_nids, /* ADC0 */
12466 .capsrc_nids = alc262_capsrc_nids,
12467 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012468 .unsol_event = alc262_ultra_unsol_event,
12469 .init_hook = alc262_ultra_automute,
12470 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012471 [ALC262_LENOVO_3000] = {
12472 .mixers = { alc262_lenovo_3000_mixer },
12473 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012474 alc262_lenovo_3000_unsol_verbs,
12475 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012476 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12477 .dac_nids = alc262_dac_nids,
12478 .hp_nid = 0x03,
12479 .dig_out_nid = ALC262_DIGOUT_NID,
12480 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12481 .channel_mode = alc262_modes,
12482 .input_mux = &alc262_fujitsu_capture_source,
12483 .unsol_event = alc262_lenovo_3000_unsol_event,
12484 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012485 [ALC262_NEC] = {
12486 .mixers = { alc262_nec_mixer },
12487 .init_verbs = { alc262_nec_verbs },
12488 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12489 .dac_nids = alc262_dac_nids,
12490 .hp_nid = 0x03,
12491 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12492 .channel_mode = alc262_modes,
12493 .input_mux = &alc262_capture_source,
12494 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012495 [ALC262_TOSHIBA_S06] = {
12496 .mixers = { alc262_toshiba_s06_mixer },
12497 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12498 alc262_eapd_verbs },
12499 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12500 .capsrc_nids = alc262_dmic_capsrc_nids,
12501 .dac_nids = alc262_dac_nids,
12502 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012503 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012504 .dig_out_nid = ALC262_DIGOUT_NID,
12505 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12506 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012507 .unsol_event = alc_sku_unsol_event,
12508 .setup = alc262_toshiba_s06_setup,
12509 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012510 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012511 [ALC262_TOSHIBA_RX1] = {
12512 .mixers = { alc262_toshiba_rx1_mixer },
12513 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12514 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12515 .dac_nids = alc262_dac_nids,
12516 .hp_nid = 0x03,
12517 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12518 .channel_mode = alc262_modes,
12519 .input_mux = &alc262_capture_source,
12520 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012521 .setup = alc262_hippo_setup,
12522 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012523 },
Tony Vroonba340e82009-02-02 19:01:30 +000012524 [ALC262_TYAN] = {
12525 .mixers = { alc262_tyan_mixer },
12526 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12527 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12528 .dac_nids = alc262_dac_nids,
12529 .hp_nid = 0x02,
12530 .dig_out_nid = ALC262_DIGOUT_NID,
12531 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12532 .channel_mode = alc262_modes,
12533 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012534 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012535 .setup = alc262_tyan_setup,
12536 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012537 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012538};
12539
12540static int patch_alc262(struct hda_codec *codec)
12541{
12542 struct alc_spec *spec;
12543 int board_config;
12544 int err;
12545
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012546 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012547 if (spec == NULL)
12548 return -ENOMEM;
12549
12550 codec->spec = spec;
12551#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012552 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12553 * under-run
12554 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012555 {
12556 int tmp;
12557 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12558 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12559 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12560 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12561 }
12562#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012563 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012564
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012565 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12566
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012567 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12568 alc262_models,
12569 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012570
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012571 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012572 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12573 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012574 board_config = ALC262_AUTO;
12575 }
12576
12577 if (board_config == ALC262_AUTO) {
12578 /* automatic parse from the BIOS config */
12579 err = alc262_parse_auto_config(codec);
12580 if (err < 0) {
12581 alc_free(codec);
12582 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012583 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012584 printk(KERN_INFO
12585 "hda_codec: Cannot set up configuration "
12586 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012587 board_config = ALC262_BASIC;
12588 }
12589 }
12590
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012591 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012592 err = snd_hda_attach_beep_device(codec, 0x1);
12593 if (err < 0) {
12594 alc_free(codec);
12595 return err;
12596 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012597 }
12598
Kailang Yangdf694da2005-12-05 19:42:22 +010012599 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012600 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012601
Kailang Yangdf694da2005-12-05 19:42:22 +010012602 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12603 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012604
Kailang Yangdf694da2005-12-05 19:42:22 +010012605 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12606 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12607
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012608 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012609 int i;
12610 /* check whether the digital-mic has to be supported */
12611 for (i = 0; i < spec->input_mux->num_items; i++) {
12612 if (spec->input_mux->items[i].index >= 9)
12613 break;
12614 }
12615 if (i < spec->input_mux->num_items) {
12616 /* use only ADC0 */
12617 spec->adc_nids = alc262_dmic_adc_nids;
12618 spec->num_adc_nids = 1;
12619 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012620 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012621 /* all analog inputs */
12622 /* check whether NID 0x07 is valid */
12623 unsigned int wcap = get_wcaps(codec, 0x07);
12624
12625 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012626 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012627 if (wcap != AC_WID_AUD_IN) {
12628 spec->adc_nids = alc262_adc_nids_alt;
12629 spec->num_adc_nids =
12630 ARRAY_SIZE(alc262_adc_nids_alt);
12631 spec->capsrc_nids = alc262_capsrc_nids_alt;
12632 } else {
12633 spec->adc_nids = alc262_adc_nids;
12634 spec->num_adc_nids =
12635 ARRAY_SIZE(alc262_adc_nids);
12636 spec->capsrc_nids = alc262_capsrc_nids;
12637 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012638 }
12639 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012640 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012641 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012642 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012643 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012644
Takashi Iwai2134ea42008-01-10 16:53:55 +010012645 spec->vmaster_nid = 0x0c;
12646
Kailang Yangdf694da2005-12-05 19:42:22 +010012647 codec->patch_ops = alc_patch_ops;
12648 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012649 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012650#ifdef CONFIG_SND_HDA_POWER_SAVE
12651 if (!spec->loopback.amplist)
12652 spec->loopback.amplist = alc262_loopbacks;
12653#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012654
Kailang Yangdf694da2005-12-05 19:42:22 +010012655 return 0;
12656}
12657
Kailang Yangdf694da2005-12-05 19:42:22 +010012658/*
Kailang Yanga361d842007-06-05 12:30:55 +020012659 * ALC268 channel source setting (2 channel)
12660 */
12661#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12662#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012663
Kailang Yanga361d842007-06-05 12:30:55 +020012664static hda_nid_t alc268_dac_nids[2] = {
12665 /* front, hp */
12666 0x02, 0x03
12667};
12668
12669static hda_nid_t alc268_adc_nids[2] = {
12670 /* ADC0-1 */
12671 0x08, 0x07
12672};
12673
12674static hda_nid_t alc268_adc_nids_alt[1] = {
12675 /* ADC0 */
12676 0x08
12677};
12678
Takashi Iwaie1406342008-02-11 18:32:32 +010012679static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12680
Kailang Yanga361d842007-06-05 12:30:55 +020012681static struct snd_kcontrol_new alc268_base_mixer[] = {
12682 /* output mixer control */
12683 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12684 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12685 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12686 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012687 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12688 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12689 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012690 { }
12691};
12692
Takashi Iwai42171c12009-05-08 14:11:43 +020012693static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12694 /* output mixer control */
12695 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12696 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12697 ALC262_HIPPO_MASTER_SWITCH,
12698 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12699 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12700 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12701 { }
12702};
12703
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012704/* bind Beep switches of both NID 0x0f and 0x10 */
12705static struct hda_bind_ctls alc268_bind_beep_sw = {
12706 .ops = &snd_hda_bind_sw,
12707 .values = {
12708 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12709 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12710 0
12711 },
12712};
12713
12714static struct snd_kcontrol_new alc268_beep_mixer[] = {
12715 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12716 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12717 { }
12718};
12719
Kailang Yangd1a991a2007-08-15 16:21:59 +020012720static struct hda_verb alc268_eapd_verbs[] = {
12721 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12722 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12723 { }
12724};
12725
Takashi Iwaid2738092007-08-16 14:59:45 +020012726/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012727static struct hda_verb alc268_toshiba_verbs[] = {
12728 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12729 { } /* end */
12730};
12731
12732/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012733/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012734static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12735 .ops = &snd_hda_bind_vol,
12736 .values = {
12737 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12738 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12739 0
12740 },
12741};
12742
Takashi Iwai889c4392007-08-23 18:56:52 +020012743/* mute/unmute internal speaker according to the hp jack and mute state */
12744static void alc268_acer_automute(struct hda_codec *codec, int force)
12745{
12746 struct alc_spec *spec = codec->spec;
12747 unsigned int mute;
12748
12749 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012750 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012751 spec->sense_updated = 1;
12752 }
12753 if (spec->jack_present)
12754 mute = HDA_AMP_MUTE; /* mute internal speaker */
12755 else /* unmute internal speaker if necessary */
12756 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12757 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12758 HDA_AMP_MUTE, mute);
12759}
12760
12761
12762/* bind hp and internal speaker mute (with plug check) */
12763static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12764 struct snd_ctl_elem_value *ucontrol)
12765{
12766 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12767 long *valp = ucontrol->value.integer.value;
12768 int change;
12769
Takashi Iwai8de56b72009-07-24 16:51:47 +020012770 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012771 if (change)
12772 alc268_acer_automute(codec, 0);
12773 return change;
12774}
Takashi Iwaid2738092007-08-16 14:59:45 +020012775
Kailang Yang8ef355d2008-08-26 13:10:22 +020012776static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12777 /* output mixer control */
12778 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12779 {
12780 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12781 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012782 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012783 .info = snd_hda_mixer_amp_switch_info,
12784 .get = snd_hda_mixer_amp_switch_get,
12785 .put = alc268_acer_master_sw_put,
12786 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12787 },
12788 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12789 { }
12790};
12791
Takashi Iwaid2738092007-08-16 14:59:45 +020012792static struct snd_kcontrol_new alc268_acer_mixer[] = {
12793 /* output mixer control */
12794 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12795 {
12796 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12797 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012798 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020012799 .info = snd_hda_mixer_amp_switch_info,
12800 .get = snd_hda_mixer_amp_switch_get,
12801 .put = alc268_acer_master_sw_put,
12802 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12803 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012804 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12805 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12806 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012807 { }
12808};
12809
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012810static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12811 /* output mixer control */
12812 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12813 {
12814 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12815 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012816 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012817 .info = snd_hda_mixer_amp_switch_info,
12818 .get = snd_hda_mixer_amp_switch_get,
12819 .put = alc268_acer_master_sw_put,
12820 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12821 },
12822 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12823 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12824 { }
12825};
12826
Kailang Yang8ef355d2008-08-26 13:10:22 +020012827static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12828 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12829 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12830 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12831 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12832 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12833 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12834 { }
12835};
12836
Takashi Iwaid2738092007-08-16 14:59:45 +020012837static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012838 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12839 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012840 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12841 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012842 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12843 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012844 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12845 { }
12846};
12847
12848/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012849#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012850#define alc268_toshiba_setup alc262_hippo_setup
12851#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012852
12853static void alc268_acer_unsol_event(struct hda_codec *codec,
12854 unsigned int res)
12855{
Takashi Iwai889c4392007-08-23 18:56:52 +020012856 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012857 return;
12858 alc268_acer_automute(codec, 1);
12859}
12860
Takashi Iwai889c4392007-08-23 18:56:52 +020012861static void alc268_acer_init_hook(struct hda_codec *codec)
12862{
12863 alc268_acer_automute(codec, 1);
12864}
12865
Kailang Yang8ef355d2008-08-26 13:10:22 +020012866/* toggle speaker-output according to the hp-jack state */
12867static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12868{
12869 unsigned int present;
12870 unsigned char bits;
12871
Wu Fengguang864f92b2009-11-18 12:38:02 +080012872 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012873 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012874 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012875 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012876 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020012877 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012878}
12879
Kailang Yang8ef355d2008-08-26 13:10:22 +020012880static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12881 unsigned int res)
12882{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012883 switch (res >> 26) {
12884 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012885 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012886 break;
12887 case ALC880_MIC_EVENT:
12888 alc_mic_automute(codec);
12889 break;
12890 }
12891}
12892
12893static void alc268_acer_lc_setup(struct hda_codec *codec)
12894{
12895 struct alc_spec *spec = codec->spec;
12896 spec->ext_mic.pin = 0x18;
12897 spec->ext_mic.mux_idx = 0;
12898 spec->int_mic.pin = 0x12;
12899 spec->int_mic.mux_idx = 6;
12900 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012901}
12902
12903static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12904{
12905 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012906 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012907}
12908
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012909static struct snd_kcontrol_new alc268_dell_mixer[] = {
12910 /* output mixer control */
12911 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12912 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12913 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12914 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12915 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12916 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12917 { }
12918};
12919
12920static struct hda_verb alc268_dell_verbs[] = {
12921 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12922 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12923 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012924 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012925 { }
12926};
12927
12928/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012929static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012930{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012931 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012932
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012933 spec->autocfg.hp_pins[0] = 0x15;
12934 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012935 spec->ext_mic.pin = 0x18;
12936 spec->ext_mic.mux_idx = 0;
12937 spec->int_mic.pin = 0x19;
12938 spec->int_mic.mux_idx = 1;
12939 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012940}
12941
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012942static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12943 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12944 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12945 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12946 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12947 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12948 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12949 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12950 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12951 { }
12952};
12953
12954static struct hda_verb alc267_quanta_il1_verbs[] = {
12955 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12956 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12957 { }
12958};
12959
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012960static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012961{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012962 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012963 spec->autocfg.hp_pins[0] = 0x15;
12964 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012965 spec->ext_mic.pin = 0x18;
12966 spec->ext_mic.mux_idx = 0;
12967 spec->int_mic.pin = 0x19;
12968 spec->int_mic.mux_idx = 1;
12969 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012970}
12971
Kailang Yanga361d842007-06-05 12:30:55 +020012972/*
12973 * generic initialization of ADC, input mixers and output mixers
12974 */
12975static struct hda_verb alc268_base_init_verbs[] = {
12976 /* Unmute DAC0-1 and set vol = 0 */
12977 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012978 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012979
12980 /*
12981 * Set up output mixers (0x0c - 0x0e)
12982 */
12983 /* set vol=0 to output mixers */
12984 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012985 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12986
12987 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12988 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12989
12990 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12991 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12992 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12993 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12994 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12995 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12996 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12997 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12998
12999 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13000 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13001 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13002 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013003 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013004
13005 /* set PCBEEP vol = 0, mute connections */
13006 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13007 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13008 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013009
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013010 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013011
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013012 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13013 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13014 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13015 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013016
Kailang Yanga361d842007-06-05 12:30:55 +020013017 { }
13018};
13019
13020/*
13021 * generic initialization of ADC, input mixers and output mixers
13022 */
13023static struct hda_verb alc268_volume_init_verbs[] = {
13024 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013025 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13026 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013027
13028 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13029 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13030 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13031 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13032 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13033
Kailang Yanga361d842007-06-05 12:30:55 +020013034 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013035 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13036 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13037
13038 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013039 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013040
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013041 /* set PCBEEP vol = 0, mute connections */
13042 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13043 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13044 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013045
13046 { }
13047};
13048
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013049static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13050 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13051 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13052 { } /* end */
13053};
13054
Kailang Yanga361d842007-06-05 12:30:55 +020013055static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13056 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13057 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013058 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013059 { } /* end */
13060};
13061
13062static struct snd_kcontrol_new alc268_capture_mixer[] = {
13063 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13064 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13065 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13066 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013067 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013068 { } /* end */
13069};
13070
13071static struct hda_input_mux alc268_capture_source = {
13072 .num_items = 4,
13073 .items = {
13074 { "Mic", 0x0 },
13075 { "Front Mic", 0x1 },
13076 { "Line", 0x2 },
13077 { "CD", 0x3 },
13078 },
13079};
13080
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013081static struct hda_input_mux alc268_acer_capture_source = {
13082 .num_items = 3,
13083 .items = {
13084 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013085 { "Internal Mic", 0x1 },
13086 { "Line", 0x2 },
13087 },
13088};
13089
13090static struct hda_input_mux alc268_acer_dmic_capture_source = {
13091 .num_items = 3,
13092 .items = {
13093 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013094 { "Internal Mic", 0x6 },
13095 { "Line", 0x2 },
13096 },
13097};
13098
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013099#ifdef CONFIG_SND_DEBUG
13100static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013101 /* Volume widgets */
13102 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13103 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13104 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13105 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13106 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13107 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13108 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13109 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13110 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13111 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13112 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13113 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13114 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013115 /* The below appears problematic on some hardwares */
13116 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013117 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13118 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13119 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13120 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13121
13122 /* Modes for retasking pin widgets */
13123 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13124 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13125 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13126 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13127
13128 /* Controls for GPIO pins, assuming they are configured as outputs */
13129 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13130 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13131 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13132 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13133
13134 /* Switches to allow the digital SPDIF output pin to be enabled.
13135 * The ALC268 does not have an SPDIF input.
13136 */
13137 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13138
13139 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13140 * this output to turn on an external amplifier.
13141 */
13142 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13143 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13144
13145 { } /* end */
13146};
13147#endif
13148
Kailang Yanga361d842007-06-05 12:30:55 +020013149/* create input playback/capture controls for the given pin */
13150static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13151 const char *ctlname, int idx)
13152{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013153 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013154 int err;
13155
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013156 switch (nid) {
13157 case 0x14:
13158 case 0x16:
13159 dac = 0x02;
13160 break;
13161 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013162 case 0x1a: /* ALC259/269 only */
13163 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013164 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013165 dac = 0x03;
13166 break;
13167 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013168 snd_printd(KERN_WARNING "hda_codec: "
13169 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013170 return 0;
13171 }
13172 if (spec->multiout.dac_nids[0] != dac &&
13173 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013174 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013175 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013176 HDA_OUTPUT));
13177 if (err < 0)
13178 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013179 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13180 }
13181
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013182 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013183 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013184 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013185 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013186 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013187 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013188 if (err < 0)
13189 return err;
13190 return 0;
13191}
13192
13193/* add playback controls from the parsed DAC table */
13194static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13195 const struct auto_pin_cfg *cfg)
13196{
13197 hda_nid_t nid;
13198 int err;
13199
Kailang Yanga361d842007-06-05 12:30:55 +020013200 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013201
13202 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013203 if (nid) {
13204 const char *name;
13205 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13206 name = "Speaker";
13207 else
13208 name = "Front";
13209 err = alc268_new_analog_output(spec, nid, name, 0);
13210 if (err < 0)
13211 return err;
13212 }
Kailang Yanga361d842007-06-05 12:30:55 +020013213
13214 nid = cfg->speaker_pins[0];
13215 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013216 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013217 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13218 if (err < 0)
13219 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013220 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013221 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13222 if (err < 0)
13223 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013224 }
13225 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013226 if (nid) {
13227 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13228 if (err < 0)
13229 return err;
13230 }
Kailang Yanga361d842007-06-05 12:30:55 +020013231
13232 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13233 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013234 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013235 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013236 if (err < 0)
13237 return err;
13238 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013239 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013240}
13241
13242/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013243static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013244 const struct auto_pin_cfg *cfg)
13245{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013246 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013247}
13248
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013249static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13250 hda_nid_t nid, int pin_type)
13251{
13252 int idx;
13253
13254 alc_set_pin_output(codec, nid, pin_type);
13255 if (nid == 0x14 || nid == 0x16)
13256 idx = 0;
13257 else
13258 idx = 1;
13259 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13260}
13261
13262static void alc268_auto_init_multi_out(struct hda_codec *codec)
13263{
13264 struct alc_spec *spec = codec->spec;
13265 hda_nid_t nid = spec->autocfg.line_out_pins[0];
13266 if (nid) {
13267 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13268 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13269 }
13270}
13271
13272static void alc268_auto_init_hp_out(struct hda_codec *codec)
13273{
13274 struct alc_spec *spec = codec->spec;
13275 hda_nid_t pin;
13276
13277 pin = spec->autocfg.hp_pins[0];
13278 if (pin)
13279 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
13280 pin = spec->autocfg.speaker_pins[0];
13281 if (pin)
13282 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
13283}
13284
Kailang Yanga361d842007-06-05 12:30:55 +020013285static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13286{
13287 struct alc_spec *spec = codec->spec;
13288 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13289 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13290 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13291 unsigned int dac_vol1, dac_vol2;
13292
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013293 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013294 snd_hda_codec_write(codec, speaker_nid, 0,
13295 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013296 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013297 snd_hda_codec_write(codec, 0x0f, 0,
13298 AC_VERB_SET_AMP_GAIN_MUTE,
13299 AMP_IN_UNMUTE(1));
13300 snd_hda_codec_write(codec, 0x10, 0,
13301 AC_VERB_SET_AMP_GAIN_MUTE,
13302 AMP_IN_UNMUTE(1));
13303 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013304 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013305 snd_hda_codec_write(codec, 0x0f, 0,
13306 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13307 snd_hda_codec_write(codec, 0x10, 0,
13308 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13309 }
13310
13311 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013312 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013313 dac_vol2 = AMP_OUT_ZERO;
13314 else if (line_nid == 0x15)
13315 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013316 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013317 dac_vol2 = AMP_OUT_ZERO;
13318 else if (hp_nid == 0x15)
13319 dac_vol1 = AMP_OUT_ZERO;
13320 if (line_nid != 0x16 || hp_nid != 0x16 ||
13321 spec->autocfg.line_out_pins[1] != 0x16 ||
13322 spec->autocfg.line_out_pins[2] != 0x16)
13323 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13324
13325 snd_hda_codec_write(codec, 0x02, 0,
13326 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13327 snd_hda_codec_write(codec, 0x03, 0,
13328 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13329}
13330
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013331/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013332#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13333#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013334#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013335#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13336
13337/*
13338 * BIOS auto configuration
13339 */
13340static int alc268_parse_auto_config(struct hda_codec *codec)
13341{
13342 struct alc_spec *spec = codec->spec;
13343 int err;
13344 static hda_nid_t alc268_ignore[] = { 0 };
13345
13346 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13347 alc268_ignore);
13348 if (err < 0)
13349 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013350 if (!spec->autocfg.line_outs) {
13351 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13352 spec->multiout.max_channels = 2;
13353 spec->no_analog = 1;
13354 goto dig_only;
13355 }
Kailang Yanga361d842007-06-05 12:30:55 +020013356 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013357 }
Kailang Yanga361d842007-06-05 12:30:55 +020013358 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13359 if (err < 0)
13360 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013361 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013362 if (err < 0)
13363 return err;
13364
13365 spec->multiout.max_channels = 2;
13366
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013367 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013368 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013369 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013370 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013371 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013372
Takashi Iwai892981f2009-03-02 08:04:35 +010013373 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013374 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013375
Takashi Iwaid88897e2008-10-31 15:01:37 +010013376 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013377 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013378 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013379
Takashi Iwai776e1842007-08-29 15:07:11 +020013380 err = alc_auto_add_mic_boost(codec);
13381 if (err < 0)
13382 return err;
13383
Kailang Yang6227cdc2010-02-25 08:36:52 +010013384 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013385
Kailang Yanga361d842007-06-05 12:30:55 +020013386 return 1;
13387}
13388
Kailang Yanga361d842007-06-05 12:30:55 +020013389#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13390
13391/* init callback for auto-configuration model -- overriding the default init */
13392static void alc268_auto_init(struct hda_codec *codec)
13393{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013394 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013395 alc268_auto_init_multi_out(codec);
13396 alc268_auto_init_hp_out(codec);
13397 alc268_auto_init_mono_speaker_out(codec);
13398 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013399 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013400 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013401 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013402}
13403
13404/*
13405 * configuration and preset
13406 */
13407static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013408 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013409 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013410 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013411 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013412 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013413 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013414 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013415 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013416#ifdef CONFIG_SND_DEBUG
13417 [ALC268_TEST] = "test",
13418#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013419 [ALC268_AUTO] = "auto",
13420};
13421
13422static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013423 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013424 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013425 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013426 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013427 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013428 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13429 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013430 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013431 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13432 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013433 /* almost compatible with toshiba but with optional digital outs;
13434 * auto-probing seems working fine
13435 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013436 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013437 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013438 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013439 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013440 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013441 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013442 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013443 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020013444 {}
13445};
13446
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013447/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13448static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13449 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13450 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13451 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13452 ALC268_TOSHIBA),
13453 {}
13454};
13455
Kailang Yanga361d842007-06-05 12:30:55 +020013456static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013457 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013458 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13459 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013460 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13461 alc267_quanta_il1_verbs },
13462 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13463 .dac_nids = alc268_dac_nids,
13464 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13465 .adc_nids = alc268_adc_nids_alt,
13466 .hp_nid = 0x03,
13467 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13468 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013469 .unsol_event = alc_sku_unsol_event,
13470 .setup = alc267_quanta_il1_setup,
13471 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013472 },
Kailang Yanga361d842007-06-05 12:30:55 +020013473 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013474 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13475 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013476 .init_verbs = { alc268_base_init_verbs },
13477 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13478 .dac_nids = alc268_dac_nids,
13479 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13480 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013481 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013482 .hp_nid = 0x03,
13483 .dig_out_nid = ALC268_DIGOUT_NID,
13484 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13485 .channel_mode = alc268_modes,
13486 .input_mux = &alc268_capture_source,
13487 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013488 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013489 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013490 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013491 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13492 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013493 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13494 .dac_nids = alc268_dac_nids,
13495 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13496 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013497 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013498 .hp_nid = 0x03,
13499 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13500 .channel_mode = alc268_modes,
13501 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013502 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013503 .setup = alc268_toshiba_setup,
13504 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013505 },
13506 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013507 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013508 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013509 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13510 alc268_acer_verbs },
13511 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13512 .dac_nids = alc268_dac_nids,
13513 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13514 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013515 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013516 .hp_nid = 0x02,
13517 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13518 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013519 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013520 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013521 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013522 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013523 [ALC268_ACER_DMIC] = {
13524 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13525 alc268_beep_mixer },
13526 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13527 alc268_acer_verbs },
13528 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13529 .dac_nids = alc268_dac_nids,
13530 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13531 .adc_nids = alc268_adc_nids_alt,
13532 .capsrc_nids = alc268_capsrc_nids,
13533 .hp_nid = 0x02,
13534 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13535 .channel_mode = alc268_modes,
13536 .input_mux = &alc268_acer_dmic_capture_source,
13537 .unsol_event = alc268_acer_unsol_event,
13538 .init_hook = alc268_acer_init_hook,
13539 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013540 [ALC268_ACER_ASPIRE_ONE] = {
13541 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013542 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013543 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013544 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13545 alc268_acer_aspire_one_verbs },
13546 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13547 .dac_nids = alc268_dac_nids,
13548 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13549 .adc_nids = alc268_adc_nids_alt,
13550 .capsrc_nids = alc268_capsrc_nids,
13551 .hp_nid = 0x03,
13552 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13553 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013554 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013555 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013556 .init_hook = alc268_acer_lc_init_hook,
13557 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013558 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013559 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13560 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013561 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13562 alc268_dell_verbs },
13563 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13564 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013565 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13566 .adc_nids = alc268_adc_nids_alt,
13567 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013568 .hp_nid = 0x02,
13569 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13570 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013571 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013572 .setup = alc268_dell_setup,
13573 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013574 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013575 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013576 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13577 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013578 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13579 alc268_toshiba_verbs },
13580 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13581 .dac_nids = alc268_dac_nids,
13582 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13583 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013584 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013585 .hp_nid = 0x03,
13586 .dig_out_nid = ALC268_DIGOUT_NID,
13587 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13588 .channel_mode = alc268_modes,
13589 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013590 .setup = alc268_toshiba_setup,
13591 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013592 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013593#ifdef CONFIG_SND_DEBUG
13594 [ALC268_TEST] = {
13595 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13596 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13597 alc268_volume_init_verbs },
13598 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13599 .dac_nids = alc268_dac_nids,
13600 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13601 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013602 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013603 .hp_nid = 0x03,
13604 .dig_out_nid = ALC268_DIGOUT_NID,
13605 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13606 .channel_mode = alc268_modes,
13607 .input_mux = &alc268_capture_source,
13608 },
13609#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013610};
13611
13612static int patch_alc268(struct hda_codec *codec)
13613{
13614 struct alc_spec *spec;
13615 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013616 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013617
Julia Lawallef86f582009-12-19 08:18:03 +010013618 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013619 if (spec == NULL)
13620 return -ENOMEM;
13621
13622 codec->spec = spec;
13623
13624 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13625 alc268_models,
13626 alc268_cfg_tbl);
13627
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013628 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13629 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013630 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013631
Kailang Yanga361d842007-06-05 12:30:55 +020013632 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013633 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13634 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013635 board_config = ALC268_AUTO;
13636 }
13637
13638 if (board_config == ALC268_AUTO) {
13639 /* automatic parse from the BIOS config */
13640 err = alc268_parse_auto_config(codec);
13641 if (err < 0) {
13642 alc_free(codec);
13643 return err;
13644 } else if (!err) {
13645 printk(KERN_INFO
13646 "hda_codec: Cannot set up configuration "
13647 "from BIOS. Using base mode...\n");
13648 board_config = ALC268_3ST;
13649 }
13650 }
13651
13652 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013653 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013654
Kailang Yanga361d842007-06-05 12:30:55 +020013655 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13656 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013657 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013658
Kailang Yanga361d842007-06-05 12:30:55 +020013659 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13660
Takashi Iwai22971e32009-02-10 11:56:44 +010013661 has_beep = 0;
13662 for (i = 0; i < spec->num_mixers; i++) {
13663 if (spec->mixers[i] == alc268_beep_mixer) {
13664 has_beep = 1;
13665 break;
13666 }
13667 }
13668
13669 if (has_beep) {
13670 err = snd_hda_attach_beep_device(codec, 0x1);
13671 if (err < 0) {
13672 alc_free(codec);
13673 return err;
13674 }
13675 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13676 /* override the amp caps for beep generator */
13677 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013678 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13679 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13680 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13681 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013682 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013683
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013684 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013685 /* check whether NID 0x07 is valid */
13686 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013687 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013688
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013689 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013690 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013691 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013692 if (spec->auto_mic ||
13693 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013694 spec->adc_nids = alc268_adc_nids_alt;
13695 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013696 if (spec->auto_mic)
13697 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013698 if (spec->auto_mic || spec->input_mux->num_items == 1)
13699 add_mixer(spec, alc268_capture_nosrc_mixer);
13700 else
13701 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013702 } else {
13703 spec->adc_nids = alc268_adc_nids;
13704 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013705 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013706 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013707 /* set default input source */
13708 for (i = 0; i < spec->num_adc_nids; i++)
13709 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13710 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013711 i < spec->num_mux_defs ?
13712 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013713 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013714 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013715
13716 spec->vmaster_nid = 0x02;
13717
Kailang Yanga361d842007-06-05 12:30:55 +020013718 codec->patch_ops = alc_patch_ops;
13719 if (board_config == ALC268_AUTO)
13720 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013721
Kailang Yanga361d842007-06-05 12:30:55 +020013722 return 0;
13723}
13724
13725/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013726 * ALC269 channel source setting (2 channel)
13727 */
13728#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13729
13730#define alc269_dac_nids alc260_dac_nids
13731
13732static hda_nid_t alc269_adc_nids[1] = {
13733 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013734 0x08,
13735};
13736
Takashi Iwaie01bf502008-08-21 16:25:07 +020013737static hda_nid_t alc269_capsrc_nids[1] = {
13738 0x23,
13739};
13740
Kailang Yang84898e82010-02-04 14:16:14 +010013741static hda_nid_t alc269vb_adc_nids[1] = {
13742 /* ADC1 */
13743 0x09,
13744};
13745
13746static hda_nid_t alc269vb_capsrc_nids[1] = {
13747 0x22,
13748};
13749
Takashi Iwai66946352010-03-29 17:21:45 +020013750static hda_nid_t alc269_adc_candidates[] = {
13751 0x08, 0x09, 0x07,
13752};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013753
Kailang Yangf6a92242007-12-13 16:52:54 +010013754#define alc269_modes alc260_modes
13755#define alc269_capture_source alc880_lg_lw_capture_source
13756
13757static struct snd_kcontrol_new alc269_base_mixer[] = {
13758 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13759 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13760 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13761 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13762 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13763 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13764 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13765 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13766 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13767 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13768 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13769 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13770 { } /* end */
13771};
13772
Kailang Yang60db6b52008-08-26 13:13:00 +020013773static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13774 /* output mixer control */
13775 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13776 {
13777 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13778 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013779 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013780 .info = snd_hda_mixer_amp_switch_info,
13781 .get = snd_hda_mixer_amp_switch_get,
13782 .put = alc268_acer_master_sw_put,
13783 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13784 },
13785 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13786 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13787 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13788 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13789 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13790 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013791 { }
13792};
13793
Tony Vroon64154832008-11-06 15:08:49 +000013794static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13795 /* output mixer control */
13796 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13797 {
13798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13799 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013800 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013801 .info = snd_hda_mixer_amp_switch_info,
13802 .get = snd_hda_mixer_amp_switch_get,
13803 .put = alc268_acer_master_sw_put,
13804 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13805 },
13806 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13807 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13808 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13809 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13810 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13811 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13812 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13813 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13814 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013815 { }
13816};
13817
Kailang Yang84898e82010-02-04 14:16:14 +010013818static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013819 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013820 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013822 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013823 { } /* end */
13824};
13825
Kailang Yang84898e82010-02-04 14:16:14 +010013826static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
13827 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13828 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13829 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13830 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13831 { } /* end */
13832};
13833
Kailang Yangf6a92242007-12-13 16:52:54 +010013834/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010013835static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
13836 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13837 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13838 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13839 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13840 { } /* end */
13841};
13842
13843static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013844 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13845 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013846 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13847 { } /* end */
13848};
13849
Kailang Yang84898e82010-02-04 14:16:14 +010013850static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
13851 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13852 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13853 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13854 HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
13855 { } /* end */
13856};
13857
13858static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
13859 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13860 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13861 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13862 { } /* end */
13863};
13864
Takashi Iwai26f5df22008-11-03 17:39:46 +010013865/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013866#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013867
Kailang Yang60db6b52008-08-26 13:13:00 +020013868static struct hda_verb alc269_quanta_fl1_verbs[] = {
13869 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13870 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13871 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13872 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13873 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13874 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13875 { }
13876};
13877
Tony Vroon64154832008-11-06 15:08:49 +000013878static struct hda_verb alc269_lifebook_verbs[] = {
13879 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13880 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13881 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13882 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13883 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13884 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13885 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13886 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13887 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13888 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13889 { }
13890};
13891
Kailang Yang60db6b52008-08-26 13:13:00 +020013892/* toggle speaker-output according to the hp-jack state */
13893static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13894{
13895 unsigned int present;
13896 unsigned char bits;
13897
Wu Fengguang864f92b2009-11-18 12:38:02 +080013898 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013899 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020013900 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013901 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013902 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013903 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020013904
13905 snd_hda_codec_write(codec, 0x20, 0,
13906 AC_VERB_SET_COEF_INDEX, 0x0c);
13907 snd_hda_codec_write(codec, 0x20, 0,
13908 AC_VERB_SET_PROC_COEF, 0x680);
13909
13910 snd_hda_codec_write(codec, 0x20, 0,
13911 AC_VERB_SET_COEF_INDEX, 0x0c);
13912 snd_hda_codec_write(codec, 0x20, 0,
13913 AC_VERB_SET_PROC_COEF, 0x480);
13914}
13915
Tony Vroon64154832008-11-06 15:08:49 +000013916/* toggle speaker-output according to the hp-jacks state */
13917static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13918{
13919 unsigned int present;
13920 unsigned char bits;
13921
13922 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013923 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013924
13925 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013926 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013927
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013928 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000013929 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013930 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013931 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013932 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000013933
13934 snd_hda_codec_write(codec, 0x20, 0,
13935 AC_VERB_SET_COEF_INDEX, 0x0c);
13936 snd_hda_codec_write(codec, 0x20, 0,
13937 AC_VERB_SET_PROC_COEF, 0x680);
13938
13939 snd_hda_codec_write(codec, 0x20, 0,
13940 AC_VERB_SET_COEF_INDEX, 0x0c);
13941 snd_hda_codec_write(codec, 0x20, 0,
13942 AC_VERB_SET_PROC_COEF, 0x480);
13943}
13944
Tony Vroon64154832008-11-06 15:08:49 +000013945static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13946{
13947 unsigned int present_laptop;
13948 unsigned int present_dock;
13949
Wu Fengguang864f92b2009-11-18 12:38:02 +080013950 present_laptop = snd_hda_jack_detect(codec, 0x18);
13951 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013952
13953 /* Laptop mic port overrides dock mic port, design decision */
13954 if (present_dock)
13955 snd_hda_codec_write(codec, 0x23, 0,
13956 AC_VERB_SET_CONNECT_SEL, 0x3);
13957 if (present_laptop)
13958 snd_hda_codec_write(codec, 0x23, 0,
13959 AC_VERB_SET_CONNECT_SEL, 0x0);
13960 if (!present_dock && !present_laptop)
13961 snd_hda_codec_write(codec, 0x23, 0,
13962 AC_VERB_SET_CONNECT_SEL, 0x1);
13963}
13964
Kailang Yang60db6b52008-08-26 13:13:00 +020013965static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13966 unsigned int res)
13967{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013968 switch (res >> 26) {
13969 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013970 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013971 break;
13972 case ALC880_MIC_EVENT:
13973 alc_mic_automute(codec);
13974 break;
13975 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013976}
13977
Tony Vroon64154832008-11-06 15:08:49 +000013978static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13979 unsigned int res)
13980{
13981 if ((res >> 26) == ALC880_HP_EVENT)
13982 alc269_lifebook_speaker_automute(codec);
13983 if ((res >> 26) == ALC880_MIC_EVENT)
13984 alc269_lifebook_mic_autoswitch(codec);
13985}
13986
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013987static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13988{
13989 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013990 spec->autocfg.hp_pins[0] = 0x15;
13991 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013992 spec->ext_mic.pin = 0x18;
13993 spec->ext_mic.mux_idx = 0;
13994 spec->int_mic.pin = 0x19;
13995 spec->int_mic.mux_idx = 1;
13996 spec->auto_mic = 1;
13997}
13998
Kailang Yang60db6b52008-08-26 13:13:00 +020013999static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14000{
14001 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014002 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014003}
14004
Tony Vroon64154832008-11-06 15:08:49 +000014005static void alc269_lifebook_init_hook(struct hda_codec *codec)
14006{
14007 alc269_lifebook_speaker_automute(codec);
14008 alc269_lifebook_mic_autoswitch(codec);
14009}
14010
Kailang Yang84898e82010-02-04 14:16:14 +010014011static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014012 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14013 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14014 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14015 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14016 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14017 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14018 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14019 {}
14020};
14021
Kailang Yang84898e82010-02-04 14:16:14 +010014022static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014023 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14024 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14025 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14026 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14027 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14028 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14029 {}
14030};
14031
Kailang Yang84898e82010-02-04 14:16:14 +010014032static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14033 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14034 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14035 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14036 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14037 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14038 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14039 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14040 {}
14041};
14042
14043static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14044 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14045 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14046 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14047 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14048 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14049 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14050 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14051 {}
14052};
14053
Kailang Yang60db6b52008-08-26 13:13:00 +020014054/* toggle speaker-output according to the hp-jack state */
14055static void alc269_speaker_automute(struct hda_codec *codec)
14056{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014057 struct alc_spec *spec = codec->spec;
14058 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014059 unsigned int present;
14060 unsigned char bits;
14061
Kailang Yangebb83ee2009-12-17 12:23:00 +010014062 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014063 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014064 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014065 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014066 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014067 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014068}
14069
Kailang Yang60db6b52008-08-26 13:13:00 +020014070/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014071static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014072 unsigned int res)
14073{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014074 switch (res >> 26) {
14075 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014076 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014077 break;
14078 case ALC880_MIC_EVENT:
14079 alc_mic_automute(codec);
14080 break;
14081 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014082}
14083
Kailang Yang226b1ec2010-04-09 11:01:20 +020014084static void alc269_laptop_amic_setup(struct hda_codec *codec)
14085{
14086 struct alc_spec *spec = codec->spec;
14087 spec->autocfg.hp_pins[0] = 0x15;
14088 spec->autocfg.speaker_pins[0] = 0x14;
14089 spec->ext_mic.pin = 0x18;
14090 spec->ext_mic.mux_idx = 0;
14091 spec->int_mic.pin = 0x19;
14092 spec->int_mic.mux_idx = 1;
14093 spec->auto_mic = 1;
14094}
14095
Kailang Yang84898e82010-02-04 14:16:14 +010014096static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014097{
14098 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014099 spec->autocfg.hp_pins[0] = 0x15;
14100 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014101 spec->ext_mic.pin = 0x18;
14102 spec->ext_mic.mux_idx = 0;
14103 spec->int_mic.pin = 0x12;
14104 spec->int_mic.mux_idx = 5;
14105 spec->auto_mic = 1;
14106}
14107
Kailang Yang226b1ec2010-04-09 11:01:20 +020014108static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014109{
14110 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014111 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014112 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014113 spec->ext_mic.pin = 0x18;
14114 spec->ext_mic.mux_idx = 0;
14115 spec->int_mic.pin = 0x19;
14116 spec->int_mic.mux_idx = 1;
14117 spec->auto_mic = 1;
14118}
14119
Kailang Yang226b1ec2010-04-09 11:01:20 +020014120static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14121{
14122 struct alc_spec *spec = codec->spec;
14123 spec->autocfg.hp_pins[0] = 0x21;
14124 spec->autocfg.speaker_pins[0] = 0x14;
14125 spec->ext_mic.pin = 0x18;
14126 spec->ext_mic.mux_idx = 0;
14127 spec->int_mic.pin = 0x12;
14128 spec->int_mic.mux_idx = 6;
14129 spec->auto_mic = 1;
14130}
14131
Kailang Yang84898e82010-02-04 14:16:14 +010014132static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014133{
14134 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014135 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014136}
14137
Kailang Yangf6a92242007-12-13 16:52:54 +010014138/*
14139 * generic initialization of ADC, input mixers and output mixers
14140 */
14141static struct hda_verb alc269_init_verbs[] = {
14142 /*
14143 * Unmute ADC0 and set the default input to mic-in
14144 */
Kailang Yang84898e82010-02-04 14:16:14 +010014145 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014146
14147 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014148 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014149 */
14150 /* set vol=0 to output mixers */
14151 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14152 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14153
14154 /* set up input amps for analog loopback */
14155 /* Amp Indices: DAC = 0, mixer = 1 */
14156 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14157 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14158 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14159 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14160 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14161 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14162
14163 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14164 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14165 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14166 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14167 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14168 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14169 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14170
14171 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14172 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014173
Kailang Yang84898e82010-02-04 14:16:14 +010014174 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014175 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14176 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014177 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014178
14179 /* set EAPD */
14180 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014181 { }
14182};
14183
14184static struct hda_verb alc269vb_init_verbs[] = {
14185 /*
14186 * Unmute ADC0 and set the default input to mic-in
14187 */
14188 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14189
14190 /*
14191 * Set up output mixers (0x02 - 0x03)
14192 */
14193 /* set vol=0 to output mixers */
14194 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14195 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14196
14197 /* set up input amps for analog loopback */
14198 /* Amp Indices: DAC = 0, mixer = 1 */
14199 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14200 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14201 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14202 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14203 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14204 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14205
14206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14207 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14208 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14209 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14210 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14211 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14212 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14213
14214 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14215 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14216
14217 /* FIXME: use Mux-type input source selection */
14218 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14219 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14220 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14221
14222 /* set EAPD */
14223 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014224 { }
14225};
14226
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014227#define alc269_auto_create_multi_out_ctls \
14228 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014229#define alc269_auto_create_input_ctls \
14230 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014231
14232#ifdef CONFIG_SND_HDA_POWER_SAVE
14233#define alc269_loopbacks alc880_loopbacks
14234#endif
14235
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014236/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014237#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14238#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14239#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14240#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14241
Takashi Iwaif03d3112009-03-05 14:18:16 +010014242static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14243 .substreams = 1,
14244 .channels_min = 2,
14245 .channels_max = 8,
14246 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14247 /* NID is set in alc_build_pcms */
14248 .ops = {
14249 .open = alc880_playback_pcm_open,
14250 .prepare = alc880_playback_pcm_prepare,
14251 .cleanup = alc880_playback_pcm_cleanup
14252 },
14253};
14254
14255static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14256 .substreams = 1,
14257 .channels_min = 2,
14258 .channels_max = 2,
14259 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14260 /* NID is set in alc_build_pcms */
14261};
14262
Takashi Iwaiad358792010-03-30 18:00:59 +020014263#ifdef CONFIG_SND_HDA_POWER_SAVE
14264static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14265{
14266 switch (codec->subsystem_id) {
14267 case 0x103c1586:
14268 return 1;
14269 }
14270 return 0;
14271}
14272
14273static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14274{
14275 /* update mute-LED according to the speaker mute state */
14276 if (nid == 0x01 || nid == 0x14) {
14277 int pinval;
14278 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14279 HDA_AMP_MUTE)
14280 pinval = 0x24;
14281 else
14282 pinval = 0x20;
14283 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014284 snd_hda_codec_update_cache(codec, 0x19, 0,
14285 AC_VERB_SET_PIN_WIDGET_CONTROL,
14286 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014287 }
14288 return alc_check_power_status(codec, nid);
14289}
14290#endif /* CONFIG_SND_HDA_POWER_SAVE */
14291
Takashi Iwai840b64c2010-07-13 22:49:01 +020014292static int alc275_setup_dual_adc(struct hda_codec *codec)
14293{
14294 struct alc_spec *spec = codec->spec;
14295
14296 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14297 return 0;
14298 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14299 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14300 if (spec->ext_mic.pin <= 0x12) {
14301 spec->private_adc_nids[0] = 0x08;
14302 spec->private_adc_nids[1] = 0x11;
14303 spec->private_capsrc_nids[0] = 0x23;
14304 spec->private_capsrc_nids[1] = 0x22;
14305 } else {
14306 spec->private_adc_nids[0] = 0x11;
14307 spec->private_adc_nids[1] = 0x08;
14308 spec->private_capsrc_nids[0] = 0x22;
14309 spec->private_capsrc_nids[1] = 0x23;
14310 }
14311 spec->adc_nids = spec->private_adc_nids;
14312 spec->capsrc_nids = spec->private_capsrc_nids;
14313 spec->num_adc_nids = 2;
14314 spec->dual_adc_switch = 1;
14315 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14316 spec->adc_nids[0], spec->adc_nids[1]);
14317 return 1;
14318 }
14319 return 0;
14320}
14321
Kailang Yangf6a92242007-12-13 16:52:54 +010014322/*
14323 * BIOS auto configuration
14324 */
14325static int alc269_parse_auto_config(struct hda_codec *codec)
14326{
14327 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014328 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014329 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14330
14331 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14332 alc269_ignore);
14333 if (err < 0)
14334 return err;
14335
14336 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14337 if (err < 0)
14338 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014339 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010014340 if (err < 0)
14341 return err;
14342
14343 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14344
Takashi Iwai757899a2010-07-30 10:48:14 +020014345 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014346
Takashi Iwai603c4012008-07-30 15:01:44 +020014347 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014348 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014349
Kailang Yang84898e82010-02-04 14:16:14 +010014350 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
14351 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014352 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014353 } else {
14354 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014355 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014356 }
14357
Kailang Yangf6a92242007-12-13 16:52:54 +010014358 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014359 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014360
14361 if (!alc275_setup_dual_adc(codec))
14362 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14363 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014364
Takashi Iwaie01bf502008-08-21 16:25:07 +020014365 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014366 if (!spec->dual_adc_switch)
14367 snd_hda_codec_write_cache(codec, spec->capsrc_nids[0],
Takashi Iwaie01bf502008-08-21 16:25:07 +020014368 0, AC_VERB_SET_CONNECT_SEL,
14369 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014370
14371 err = alc_auto_add_mic_boost(codec);
14372 if (err < 0)
14373 return err;
14374
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014375 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014376 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014377
Kailang Yangf6a92242007-12-13 16:52:54 +010014378 return 1;
14379}
14380
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014381#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14382#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014383#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14384
14385
14386/* init callback for auto-configuration model -- overriding the default init */
14387static void alc269_auto_init(struct hda_codec *codec)
14388{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014389 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014390 alc269_auto_init_multi_out(codec);
14391 alc269_auto_init_hp_out(codec);
14392 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014393 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014394 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014395 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014396}
14397
Takashi Iwaiff818c22010-04-12 08:59:25 +020014398enum {
14399 ALC269_FIXUP_SONY_VAIO,
14400};
14401
Tobias Klauserfbc25662010-05-20 10:40:55 +020014402static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
Takashi Iwaiff818c22010-04-12 08:59:25 +020014403 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14404 {}
14405};
14406
14407static const struct alc_fixup alc269_fixups[] = {
14408 [ALC269_FIXUP_SONY_VAIO] = {
14409 .verbs = alc269_sony_vaio_fixup_verbs
14410 },
14411};
14412
14413static struct snd_pci_quirk alc269_fixup_tbl[] = {
14414 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
14415 {}
14416};
14417
14418
Kailang Yangf6a92242007-12-13 16:52:54 +010014419/*
14420 * configuration and preset
14421 */
14422static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014423 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014424 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014425 [ALC269_AMIC] = "laptop-amic",
14426 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014427 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014428 [ALC269_LIFEBOOK] = "lifebook",
14429 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014430};
14431
14432static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014433 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020014434 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014435 ALC269_AMIC),
14436 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14437 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14438 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14439 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14440 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14441 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14442 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14443 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14444 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14445 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14446 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14447 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14448 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14449 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14450 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14451 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14452 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14453 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14454 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14455 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14456 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14457 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14458 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14459 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14460 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14461 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14462 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14463 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14464 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14465 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14466 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14467 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14468 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14469 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14470 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14471 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014472 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014473 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014474 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014475 ALC269_DMIC),
14476 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14477 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014478 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014479 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014480 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14481 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14482 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14483 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14484 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14485 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014486 {}
14487};
14488
14489static struct alc_config_preset alc269_presets[] = {
14490 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014491 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014492 .init_verbs = { alc269_init_verbs },
14493 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14494 .dac_nids = alc269_dac_nids,
14495 .hp_nid = 0x03,
14496 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14497 .channel_mode = alc269_modes,
14498 .input_mux = &alc269_capture_source,
14499 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014500 [ALC269_QUANTA_FL1] = {
14501 .mixers = { alc269_quanta_fl1_mixer },
14502 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14503 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14504 .dac_nids = alc269_dac_nids,
14505 .hp_nid = 0x03,
14506 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14507 .channel_mode = alc269_modes,
14508 .input_mux = &alc269_capture_source,
14509 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014510 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014511 .init_hook = alc269_quanta_fl1_init_hook,
14512 },
Kailang Yang84898e82010-02-04 14:16:14 +010014513 [ALC269_AMIC] = {
14514 .mixers = { alc269_laptop_mixer },
14515 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014516 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014517 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014518 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14519 .dac_nids = alc269_dac_nids,
14520 .hp_nid = 0x03,
14521 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14522 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014523 .unsol_event = alc269_laptop_unsol_event,
14524 .setup = alc269_laptop_amic_setup,
14525 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014526 },
Kailang Yang84898e82010-02-04 14:16:14 +010014527 [ALC269_DMIC] = {
14528 .mixers = { alc269_laptop_mixer },
14529 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014530 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014531 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014532 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14533 .dac_nids = alc269_dac_nids,
14534 .hp_nid = 0x03,
14535 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14536 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014537 .unsol_event = alc269_laptop_unsol_event,
14538 .setup = alc269_laptop_dmic_setup,
14539 .init_hook = alc269_laptop_inithook,
14540 },
14541 [ALC269VB_AMIC] = {
14542 .mixers = { alc269vb_laptop_mixer },
14543 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14544 .init_verbs = { alc269vb_init_verbs,
14545 alc269vb_laptop_amic_init_verbs },
14546 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14547 .dac_nids = alc269_dac_nids,
14548 .hp_nid = 0x03,
14549 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14550 .channel_mode = alc269_modes,
14551 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014552 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014553 .init_hook = alc269_laptop_inithook,
14554 },
14555 [ALC269VB_DMIC] = {
14556 .mixers = { alc269vb_laptop_mixer },
14557 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14558 .init_verbs = { alc269vb_init_verbs,
14559 alc269vb_laptop_dmic_init_verbs },
14560 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14561 .dac_nids = alc269_dac_nids,
14562 .hp_nid = 0x03,
14563 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14564 .channel_mode = alc269_modes,
14565 .unsol_event = alc269_laptop_unsol_event,
14566 .setup = alc269vb_laptop_dmic_setup,
14567 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014568 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014569 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014570 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014571 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014572 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014573 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014574 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14575 .dac_nids = alc269_dac_nids,
14576 .hp_nid = 0x03,
14577 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14578 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014579 .unsol_event = alc269_laptop_unsol_event,
14580 .setup = alc269_laptop_dmic_setup,
14581 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014582 },
Tony Vroon64154832008-11-06 15:08:49 +000014583 [ALC269_LIFEBOOK] = {
14584 .mixers = { alc269_lifebook_mixer },
14585 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14586 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14587 .dac_nids = alc269_dac_nids,
14588 .hp_nid = 0x03,
14589 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14590 .channel_mode = alc269_modes,
14591 .input_mux = &alc269_capture_source,
14592 .unsol_event = alc269_lifebook_unsol_event,
14593 .init_hook = alc269_lifebook_init_hook,
14594 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014595};
14596
14597static int patch_alc269(struct hda_codec *codec)
14598{
14599 struct alc_spec *spec;
14600 int board_config;
14601 int err;
Kailang Yang84898e82010-02-04 14:16:14 +010014602 int is_alc269vb = 0;
Kailang Yangf6a92242007-12-13 16:52:54 +010014603
14604 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14605 if (spec == NULL)
14606 return -ENOMEM;
14607
14608 codec->spec = spec;
14609
Kailang Yangda00c242010-03-19 11:23:45 +010014610 alc_auto_parse_customize_define(codec);
14611
Kailang Yang274693f2009-12-03 10:07:50 +010014612 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
Kailang Yangc027ddc2010-03-19 11:33:06 +010014613 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14614 spec->cdefine.platform_type == 1)
14615 alc_codec_rename(codec, "ALC271X");
14616 else
14617 alc_codec_rename(codec, "ALC259");
Kailang Yang84898e82010-02-04 14:16:14 +010014618 is_alc269vb = 1;
Kailang Yangc027ddc2010-03-19 11:33:06 +010014619 } else
14620 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Kailang Yang274693f2009-12-03 10:07:50 +010014621
Kailang Yangf6a92242007-12-13 16:52:54 +010014622 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14623 alc269_models,
14624 alc269_cfg_tbl);
14625
14626 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014627 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14628 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014629 board_config = ALC269_AUTO;
14630 }
14631
Takashi Iwaiff818c22010-04-12 08:59:25 +020014632 if (board_config == ALC269_AUTO)
14633 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
14634
Kailang Yangf6a92242007-12-13 16:52:54 +010014635 if (board_config == ALC269_AUTO) {
14636 /* automatic parse from the BIOS config */
14637 err = alc269_parse_auto_config(codec);
14638 if (err < 0) {
14639 alc_free(codec);
14640 return err;
14641 } else if (!err) {
14642 printk(KERN_INFO
14643 "hda_codec: Cannot set up configuration "
14644 "from BIOS. Using base mode...\n");
14645 board_config = ALC269_BASIC;
14646 }
14647 }
14648
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014649 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014650 err = snd_hda_attach_beep_device(codec, 0x1);
14651 if (err < 0) {
14652 alc_free(codec);
14653 return err;
14654 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014655 }
14656
Kailang Yangf6a92242007-12-13 16:52:54 +010014657 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014658 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014659
Kailang Yang84898e82010-02-04 14:16:14 +010014660 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014661 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14662 * fix the sample rate of analog I/O to 44.1kHz
14663 */
14664 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14665 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020014666 } else if (spec->dual_adc_switch) {
14667 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14668 /* switch ADC dynamically */
14669 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014670 } else {
14671 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14672 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14673 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014674 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14675 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14676
Takashi Iwai66946352010-03-29 17:21:45 +020014677 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
14678 if (!is_alc269vb) {
14679 spec->adc_nids = alc269_adc_nids;
14680 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14681 spec->capsrc_nids = alc269_capsrc_nids;
14682 } else {
14683 spec->adc_nids = alc269vb_adc_nids;
14684 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14685 spec->capsrc_nids = alc269vb_capsrc_nids;
14686 }
Kailang Yang84898e82010-02-04 14:16:14 +010014687 }
14688
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014689 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014690 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014691 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014692 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014693
Takashi Iwaiff818c22010-04-12 08:59:25 +020014694 if (board_config == ALC269_AUTO)
14695 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
14696
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014697 spec->vmaster_nid = 0x02;
14698
Kailang Yangf6a92242007-12-13 16:52:54 +010014699 codec->patch_ops = alc_patch_ops;
14700 if (board_config == ALC269_AUTO)
14701 spec->init_hook = alc269_auto_init;
14702#ifdef CONFIG_SND_HDA_POWER_SAVE
14703 if (!spec->loopback.amplist)
14704 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014705 if (alc269_mic2_for_mute_led(codec))
14706 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014707#endif
14708
14709 return 0;
14710}
14711
14712/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014713 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14714 */
14715
14716/*
14717 * set the path ways for 2 channel output
14718 * need to set the codec line out and mic 1 pin widgets to inputs
14719 */
14720static struct hda_verb alc861_threestack_ch2_init[] = {
14721 /* set pin widget 1Ah (line in) for input */
14722 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014723 /* set pin widget 18h (mic1/2) for input, for mic also enable
14724 * the vref
14725 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014726 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14727
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014728 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14729#if 0
14730 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14731 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14732#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014733 { } /* end */
14734};
14735/*
14736 * 6ch mode
14737 * need to set the codec line out and mic 1 pin widgets to outputs
14738 */
14739static struct hda_verb alc861_threestack_ch6_init[] = {
14740 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14741 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14742 /* set pin widget 18h (mic1) for output (CLFE)*/
14743 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14744
14745 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014746 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014747
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014748 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14749#if 0
14750 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14751 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14752#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014753 { } /* end */
14754};
14755
14756static struct hda_channel_mode alc861_threestack_modes[2] = {
14757 { 2, alc861_threestack_ch2_init },
14758 { 6, alc861_threestack_ch6_init },
14759};
Takashi Iwai22309c32006-08-09 16:57:28 +020014760/* Set mic1 as input and unmute the mixer */
14761static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
14762 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14763 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14764 { } /* end */
14765};
14766/* Set mic1 as output and mute mixer */
14767static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
14768 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14769 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14770 { } /* end */
14771};
14772
14773static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
14774 { 2, alc861_uniwill_m31_ch2_init },
14775 { 4, alc861_uniwill_m31_ch4_init },
14776};
Kailang Yangdf694da2005-12-05 19:42:22 +010014777
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014778/* Set mic1 and line-in as input and unmute the mixer */
14779static struct hda_verb alc861_asus_ch2_init[] = {
14780 /* set pin widget 1Ah (line in) for input */
14781 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014782 /* set pin widget 18h (mic1/2) for input, for mic also enable
14783 * the vref
14784 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014785 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14786
14787 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14788#if 0
14789 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14790 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14791#endif
14792 { } /* end */
14793};
14794/* Set mic1 nad line-in as output and mute mixer */
14795static struct hda_verb alc861_asus_ch6_init[] = {
14796 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14797 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14798 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14799 /* set pin widget 18h (mic1) for output (CLFE)*/
14800 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14801 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14802 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14803 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14804
14805 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14806#if 0
14807 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14808 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14809#endif
14810 { } /* end */
14811};
14812
14813static struct hda_channel_mode alc861_asus_modes[2] = {
14814 { 2, alc861_asus_ch2_init },
14815 { 6, alc861_asus_ch6_init },
14816};
14817
Kailang Yangdf694da2005-12-05 19:42:22 +010014818/* patch-ALC861 */
14819
14820static struct snd_kcontrol_new alc861_base_mixer[] = {
14821 /* output mixer control */
14822 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14823 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14824 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14825 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14826 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14827
14828 /*Input mixer control */
14829 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14830 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14831 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14832 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14833 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14834 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14835 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14836 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14837 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14838 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014839
Kailang Yangdf694da2005-12-05 19:42:22 +010014840 { } /* end */
14841};
14842
14843static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14844 /* output mixer control */
14845 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14846 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14847 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14848 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14849 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14850
14851 /* Input mixer control */
14852 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14853 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14854 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14855 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14856 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14857 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14858 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14859 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14860 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14861 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014862
Kailang Yangdf694da2005-12-05 19:42:22 +010014863 {
14864 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14865 .name = "Channel Mode",
14866 .info = alc_ch_mode_info,
14867 .get = alc_ch_mode_get,
14868 .put = alc_ch_mode_put,
14869 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14870 },
14871 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014872};
14873
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014874static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014875 /* output mixer control */
14876 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14877 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14878 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014879
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014880 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014881};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014882
Takashi Iwai22309c32006-08-09 16:57:28 +020014883static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14884 /* output mixer control */
14885 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14886 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14887 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14888 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14889 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14890
14891 /* Input mixer control */
14892 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14893 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14894 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14895 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14896 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14897 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14898 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14899 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14900 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14901 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014902
Takashi Iwai22309c32006-08-09 16:57:28 +020014903 {
14904 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14905 .name = "Channel Mode",
14906 .info = alc_ch_mode_info,
14907 .get = alc_ch_mode_get,
14908 .put = alc_ch_mode_put,
14909 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14910 },
14911 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014912};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014913
14914static struct snd_kcontrol_new alc861_asus_mixer[] = {
14915 /* output mixer control */
14916 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14917 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14918 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14919 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14920 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14921
14922 /* Input mixer control */
14923 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14924 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14925 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14926 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14927 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14928 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14929 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14930 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14931 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014932 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14933
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014934 {
14935 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14936 .name = "Channel Mode",
14937 .info = alc_ch_mode_info,
14938 .get = alc_ch_mode_get,
14939 .put = alc_ch_mode_put,
14940 .private_value = ARRAY_SIZE(alc861_asus_modes),
14941 },
14942 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014943};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014944
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014945/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014946static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014947 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14948 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014949 { }
14950};
14951
Kailang Yangdf694da2005-12-05 19:42:22 +010014952/*
14953 * generic initialization of ADC, input mixers and output mixers
14954 */
14955static struct hda_verb alc861_base_init_verbs[] = {
14956 /*
14957 * Unmute ADC0 and set the default input to mic-in
14958 */
14959 /* port-A for surround (rear panel) */
14960 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14961 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14962 /* port-B for mic-in (rear panel) with vref */
14963 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14964 /* port-C for line-in (rear panel) */
14965 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14966 /* port-D for Front */
14967 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14968 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14969 /* port-E for HP out (front panel) */
14970 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14971 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014972 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014973 /* port-F for mic-in (front panel) with vref */
14974 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14975 /* port-G for CLFE (rear panel) */
14976 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14977 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14978 /* port-H for side (rear panel) */
14979 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14980 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14981 /* CD-in */
14982 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14983 /* route front mic to ADC1*/
14984 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14985 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014986
Kailang Yangdf694da2005-12-05 19:42:22 +010014987 /* Unmute DAC0~3 & spdif out*/
14988 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14989 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14990 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14991 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14992 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014993
Kailang Yangdf694da2005-12-05 19:42:22 +010014994 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14995 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14996 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14997 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14998 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014999
Kailang Yangdf694da2005-12-05 19:42:22 +010015000 /* Unmute Stereo Mixer 15 */
15001 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15002 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15003 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015004 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015005
15006 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15007 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15008 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15009 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15010 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15011 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15012 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15013 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015014 /* hp used DAC 3 (Front) */
15015 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015016 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15017
15018 { }
15019};
15020
15021static struct hda_verb alc861_threestack_init_verbs[] = {
15022 /*
15023 * Unmute ADC0 and set the default input to mic-in
15024 */
15025 /* port-A for surround (rear panel) */
15026 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15027 /* port-B for mic-in (rear panel) with vref */
15028 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15029 /* port-C for line-in (rear panel) */
15030 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15031 /* port-D for Front */
15032 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15033 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15034 /* port-E for HP out (front panel) */
15035 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15036 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015037 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015038 /* port-F for mic-in (front panel) with vref */
15039 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15040 /* port-G for CLFE (rear panel) */
15041 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15042 /* port-H for side (rear panel) */
15043 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15044 /* CD-in */
15045 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15046 /* route front mic to ADC1*/
15047 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15048 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15049 /* Unmute DAC0~3 & spdif out*/
15050 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15051 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15052 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15053 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15054 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015055
Kailang Yangdf694da2005-12-05 19:42:22 +010015056 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15057 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15058 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15059 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15060 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015061
Kailang Yangdf694da2005-12-05 19:42:22 +010015062 /* Unmute Stereo Mixer 15 */
15063 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15064 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15065 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015067
15068 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15069 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15070 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15071 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15072 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15073 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15074 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15075 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015076 /* hp used DAC 3 (Front) */
15077 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015078 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15079 { }
15080};
Takashi Iwai22309c32006-08-09 16:57:28 +020015081
15082static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15083 /*
15084 * Unmute ADC0 and set the default input to mic-in
15085 */
15086 /* port-A for surround (rear panel) */
15087 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15088 /* port-B for mic-in (rear panel) with vref */
15089 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15090 /* port-C for line-in (rear panel) */
15091 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15092 /* port-D for Front */
15093 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15094 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15095 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015096 /* this has to be set to VREF80 */
15097 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015098 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015099 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015100 /* port-F for mic-in (front panel) with vref */
15101 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15102 /* port-G for CLFE (rear panel) */
15103 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15104 /* port-H for side (rear panel) */
15105 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15106 /* CD-in */
15107 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15108 /* route front mic to ADC1*/
15109 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15110 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15111 /* Unmute DAC0~3 & spdif out*/
15112 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15113 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15114 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15115 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15116 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015117
Takashi Iwai22309c32006-08-09 16:57:28 +020015118 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15119 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15120 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15121 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15122 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015123
Takashi Iwai22309c32006-08-09 16:57:28 +020015124 /* Unmute Stereo Mixer 15 */
15125 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15126 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15127 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015128 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015129
15130 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15131 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15132 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15133 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15134 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15135 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15136 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15137 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015138 /* hp used DAC 3 (Front) */
15139 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015140 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15141 { }
15142};
15143
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015144static struct hda_verb alc861_asus_init_verbs[] = {
15145 /*
15146 * Unmute ADC0 and set the default input to mic-in
15147 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015148 /* port-A for surround (rear panel)
15149 * according to codec#0 this is the HP jack
15150 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015151 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15152 /* route front PCM to HP */
15153 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15154 /* port-B for mic-in (rear panel) with vref */
15155 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15156 /* port-C for line-in (rear panel) */
15157 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15158 /* port-D for Front */
15159 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15160 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15161 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015162 /* this has to be set to VREF80 */
15163 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015164 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015165 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015166 /* port-F for mic-in (front panel) with vref */
15167 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15168 /* port-G for CLFE (rear panel) */
15169 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15170 /* port-H for side (rear panel) */
15171 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15172 /* CD-in */
15173 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15174 /* route front mic to ADC1*/
15175 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15176 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15177 /* Unmute DAC0~3 & spdif out*/
15178 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15179 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15180 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15181 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15182 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15183 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15184 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15185 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15186 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15187 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015188
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015189 /* Unmute Stereo Mixer 15 */
15190 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15191 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15192 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015193 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015194
15195 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15196 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15197 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15198 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15199 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15200 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15201 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15202 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015203 /* hp used DAC 3 (Front) */
15204 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015205 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15206 { }
15207};
15208
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015209/* additional init verbs for ASUS laptops */
15210static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15211 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15212 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15213 { }
15214};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015215
Kailang Yangdf694da2005-12-05 19:42:22 +010015216/*
15217 * generic initialization of ADC, input mixers and output mixers
15218 */
15219static struct hda_verb alc861_auto_init_verbs[] = {
15220 /*
15221 * Unmute ADC0 and set the default input to mic-in
15222 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015223 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015224 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015225
Kailang Yangdf694da2005-12-05 19:42:22 +010015226 /* Unmute DAC0~3 & spdif out*/
15227 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15228 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15229 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15230 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15231 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015232
Kailang Yangdf694da2005-12-05 19:42:22 +010015233 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15234 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15235 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15236 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15237 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015238
Kailang Yangdf694da2005-12-05 19:42:22 +010015239 /* Unmute Stereo Mixer 15 */
15240 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15241 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15242 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15243 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15244
Takashi Iwai1c209302009-07-22 15:17:45 +020015245 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15246 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15247 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15248 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15249 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15250 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15251 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15252 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015253
15254 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15255 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015256 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15257 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015258 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15259 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015260 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15261 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015262
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015263 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015264
15265 { }
15266};
15267
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015268static struct hda_verb alc861_toshiba_init_verbs[] = {
15269 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015270
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015271 { }
15272};
15273
15274/* toggle speaker-output according to the hp-jack state */
15275static void alc861_toshiba_automute(struct hda_codec *codec)
15276{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015277 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015278
Takashi Iwai47fd8302007-08-10 17:11:07 +020015279 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15280 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15281 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15282 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015283}
15284
15285static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15286 unsigned int res)
15287{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015288 if ((res >> 26) == ALC880_HP_EVENT)
15289 alc861_toshiba_automute(codec);
15290}
15291
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015292/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015293#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15294#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15295#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15296#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15297
15298
15299#define ALC861_DIGOUT_NID 0x07
15300
15301static struct hda_channel_mode alc861_8ch_modes[1] = {
15302 { 8, NULL }
15303};
15304
15305static hda_nid_t alc861_dac_nids[4] = {
15306 /* front, surround, clfe, side */
15307 0x03, 0x06, 0x05, 0x04
15308};
15309
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015310static hda_nid_t alc660_dac_nids[3] = {
15311 /* front, clfe, surround */
15312 0x03, 0x05, 0x06
15313};
15314
Kailang Yangdf694da2005-12-05 19:42:22 +010015315static hda_nid_t alc861_adc_nids[1] = {
15316 /* ADC0-2 */
15317 0x08,
15318};
15319
15320static struct hda_input_mux alc861_capture_source = {
15321 .num_items = 5,
15322 .items = {
15323 { "Mic", 0x0 },
15324 { "Front Mic", 0x3 },
15325 { "Line", 0x1 },
15326 { "CD", 0x4 },
15327 { "Mixer", 0x5 },
15328 },
15329};
15330
Takashi Iwai1c209302009-07-22 15:17:45 +020015331static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15332{
15333 struct alc_spec *spec = codec->spec;
15334 hda_nid_t mix, srcs[5];
15335 int i, j, num;
15336
15337 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15338 return 0;
15339 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15340 if (num < 0)
15341 return 0;
15342 for (i = 0; i < num; i++) {
15343 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015344 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015345 if (type != AC_WID_AUD_OUT)
15346 continue;
15347 for (j = 0; j < spec->multiout.num_dacs; j++)
15348 if (spec->multiout.dac_nids[j] == srcs[i])
15349 break;
15350 if (j >= spec->multiout.num_dacs)
15351 return srcs[i];
15352 }
15353 return 0;
15354}
15355
Kailang Yangdf694da2005-12-05 19:42:22 +010015356/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015357static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015358 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015359{
Takashi Iwai1c209302009-07-22 15:17:45 +020015360 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015361 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015362 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015363
15364 spec->multiout.dac_nids = spec->private_dac_nids;
15365 for (i = 0; i < cfg->line_outs; i++) {
15366 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015367 dac = alc861_look_for_dac(codec, nid);
15368 if (!dac)
15369 continue;
15370 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015371 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015372 return 0;
15373}
15374
Takashi Iwai1c209302009-07-22 15:17:45 +020015375static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15376 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015377{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015378 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015379 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15380}
15381
15382/* add playback controls from the parsed DAC table */
15383static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15384 const struct auto_pin_cfg *cfg)
15385{
15386 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015387 static const char *chname[4] = {
15388 "Front", "Surround", NULL /*CLFE*/, "Side"
15389 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015390 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015391 int i, err;
15392
15393 if (cfg->line_outs == 1) {
15394 const char *pfx = NULL;
15395 if (!cfg->hp_outs)
15396 pfx = "Master";
15397 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15398 pfx = "Speaker";
15399 if (pfx) {
15400 nid = spec->multiout.dac_nids[0];
15401 return alc861_create_out_sw(codec, pfx, nid, 3);
15402 }
15403 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015404
15405 for (i = 0; i < cfg->line_outs; i++) {
15406 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015407 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015408 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015409 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015410 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015411 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015412 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015413 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015414 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015415 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015416 return err;
15417 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015418 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015419 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015420 return err;
15421 }
15422 }
15423 return 0;
15424}
15425
Takashi Iwai1c209302009-07-22 15:17:45 +020015426static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015427{
Takashi Iwai1c209302009-07-22 15:17:45 +020015428 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015429 int err;
15430 hda_nid_t nid;
15431
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015432 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015433 return 0;
15434
15435 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015436 nid = alc861_look_for_dac(codec, pin);
15437 if (nid) {
15438 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15439 if (err < 0)
15440 return err;
15441 spec->multiout.hp_nid = nid;
15442 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015443 }
15444 return 0;
15445}
15446
15447/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015448static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015449 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015450{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015451 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015452}
15453
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015454static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15455 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015456 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015457{
Takashi Iwai1c209302009-07-22 15:17:45 +020015458 hda_nid_t mix, srcs[5];
15459 int i, num;
15460
Jacek Luczak564c5be2008-05-03 18:41:23 +020015461 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15462 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015463 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015464 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015465 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15466 return;
15467 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15468 if (num < 0)
15469 return;
15470 for (i = 0; i < num; i++) {
15471 unsigned int mute;
15472 if (srcs[i] == dac || srcs[i] == 0x15)
15473 mute = AMP_IN_UNMUTE(i);
15474 else
15475 mute = AMP_IN_MUTE(i);
15476 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15477 mute);
15478 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015479}
15480
15481static void alc861_auto_init_multi_out(struct hda_codec *codec)
15482{
15483 struct alc_spec *spec = codec->spec;
15484 int i;
15485
15486 for (i = 0; i < spec->autocfg.line_outs; i++) {
15487 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015488 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015489 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015490 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015491 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015492 }
15493}
15494
15495static void alc861_auto_init_hp_out(struct hda_codec *codec)
15496{
15497 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015498
Takashi Iwai15870f02009-10-05 08:25:13 +020015499 if (spec->autocfg.hp_outs)
15500 alc861_auto_set_output_and_unmute(codec,
15501 spec->autocfg.hp_pins[0],
15502 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015503 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015504 if (spec->autocfg.speaker_outs)
15505 alc861_auto_set_output_and_unmute(codec,
15506 spec->autocfg.speaker_pins[0],
15507 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015508 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015509}
15510
15511static void alc861_auto_init_analog_input(struct hda_codec *codec)
15512{
15513 struct alc_spec *spec = codec->spec;
15514 int i;
15515
15516 for (i = 0; i < AUTO_PIN_LAST; i++) {
15517 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010015518 if (nid >= 0x0c && nid <= 0x11)
15519 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010015520 }
15521}
15522
15523/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015524/* return 1 if successful, 0 if the proper config is not found,
15525 * or a negative error code
15526 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015527static int alc861_parse_auto_config(struct hda_codec *codec)
15528{
15529 struct alc_spec *spec = codec->spec;
15530 int err;
15531 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
15532
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015533 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15534 alc861_ignore);
15535 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015536 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015537 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015538 return 0; /* can't find valid BIOS pin config */
15539
Takashi Iwai1c209302009-07-22 15:17:45 +020015540 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015541 if (err < 0)
15542 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015543 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015544 if (err < 0)
15545 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015546 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015547 if (err < 0)
15548 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015549 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015550 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015551 return err;
15552
15553 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15554
Takashi Iwai757899a2010-07-30 10:48:14 +020015555 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015556
Takashi Iwai603c4012008-07-30 15:01:44 +020015557 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015558 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015559
Takashi Iwaid88897e2008-10-31 15:01:37 +010015560 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010015561
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015562 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015563 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015564
15565 spec->adc_nids = alc861_adc_nids;
15566 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015567 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015568
Kailang Yang6227cdc2010-02-25 08:36:52 +010015569 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015570
Kailang Yangdf694da2005-12-05 19:42:22 +010015571 return 1;
15572}
15573
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015574/* additional initialization for auto-configuration model */
15575static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015576{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015577 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015578 alc861_auto_init_multi_out(codec);
15579 alc861_auto_init_hp_out(codec);
15580 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015581 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015582 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015583 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015584}
15585
Takashi Iwaicb53c622007-08-10 17:21:45 +020015586#ifdef CONFIG_SND_HDA_POWER_SAVE
15587static struct hda_amp_list alc861_loopbacks[] = {
15588 { 0x15, HDA_INPUT, 0 },
15589 { 0x15, HDA_INPUT, 1 },
15590 { 0x15, HDA_INPUT, 2 },
15591 { 0x15, HDA_INPUT, 3 },
15592 { } /* end */
15593};
15594#endif
15595
Kailang Yangdf694da2005-12-05 19:42:22 +010015596
15597/*
15598 * configuration and preset
15599 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015600static const char *alc861_models[ALC861_MODEL_LAST] = {
15601 [ALC861_3ST] = "3stack",
15602 [ALC660_3ST] = "3stack-660",
15603 [ALC861_3ST_DIG] = "3stack-dig",
15604 [ALC861_6ST_DIG] = "6stack-dig",
15605 [ALC861_UNIWILL_M31] = "uniwill-m31",
15606 [ALC861_TOSHIBA] = "toshiba",
15607 [ALC861_ASUS] = "asus",
15608 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15609 [ALC861_AUTO] = "auto",
15610};
15611
15612static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015613 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015614 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15615 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15616 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015617 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015618 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015619 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015620 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15621 * Any other models that need this preset?
15622 */
15623 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015624 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15625 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015626 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15627 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15628 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15629 /* FIXME: the below seems conflict */
15630 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15631 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15632 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015633 {}
15634};
15635
15636static struct alc_config_preset alc861_presets[] = {
15637 [ALC861_3ST] = {
15638 .mixers = { alc861_3ST_mixer },
15639 .init_verbs = { alc861_threestack_init_verbs },
15640 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15641 .dac_nids = alc861_dac_nids,
15642 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15643 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015644 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015645 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15646 .adc_nids = alc861_adc_nids,
15647 .input_mux = &alc861_capture_source,
15648 },
15649 [ALC861_3ST_DIG] = {
15650 .mixers = { alc861_base_mixer },
15651 .init_verbs = { alc861_threestack_init_verbs },
15652 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15653 .dac_nids = alc861_dac_nids,
15654 .dig_out_nid = ALC861_DIGOUT_NID,
15655 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15656 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015657 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015658 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15659 .adc_nids = alc861_adc_nids,
15660 .input_mux = &alc861_capture_source,
15661 },
15662 [ALC861_6ST_DIG] = {
15663 .mixers = { alc861_base_mixer },
15664 .init_verbs = { alc861_base_init_verbs },
15665 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15666 .dac_nids = alc861_dac_nids,
15667 .dig_out_nid = ALC861_DIGOUT_NID,
15668 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15669 .channel_mode = alc861_8ch_modes,
15670 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15671 .adc_nids = alc861_adc_nids,
15672 .input_mux = &alc861_capture_source,
15673 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015674 [ALC660_3ST] = {
15675 .mixers = { alc861_3ST_mixer },
15676 .init_verbs = { alc861_threestack_init_verbs },
15677 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15678 .dac_nids = alc660_dac_nids,
15679 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15680 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015681 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015682 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15683 .adc_nids = alc861_adc_nids,
15684 .input_mux = &alc861_capture_source,
15685 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015686 [ALC861_UNIWILL_M31] = {
15687 .mixers = { alc861_uniwill_m31_mixer },
15688 .init_verbs = { alc861_uniwill_m31_init_verbs },
15689 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15690 .dac_nids = alc861_dac_nids,
15691 .dig_out_nid = ALC861_DIGOUT_NID,
15692 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15693 .channel_mode = alc861_uniwill_m31_modes,
15694 .need_dac_fix = 1,
15695 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15696 .adc_nids = alc861_adc_nids,
15697 .input_mux = &alc861_capture_source,
15698 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015699 [ALC861_TOSHIBA] = {
15700 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015701 .init_verbs = { alc861_base_init_verbs,
15702 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015703 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15704 .dac_nids = alc861_dac_nids,
15705 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15706 .channel_mode = alc883_3ST_2ch_modes,
15707 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15708 .adc_nids = alc861_adc_nids,
15709 .input_mux = &alc861_capture_source,
15710 .unsol_event = alc861_toshiba_unsol_event,
15711 .init_hook = alc861_toshiba_automute,
15712 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015713 [ALC861_ASUS] = {
15714 .mixers = { alc861_asus_mixer },
15715 .init_verbs = { alc861_asus_init_verbs },
15716 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15717 .dac_nids = alc861_dac_nids,
15718 .dig_out_nid = ALC861_DIGOUT_NID,
15719 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15720 .channel_mode = alc861_asus_modes,
15721 .need_dac_fix = 1,
15722 .hp_nid = 0x06,
15723 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15724 .adc_nids = alc861_adc_nids,
15725 .input_mux = &alc861_capture_source,
15726 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015727 [ALC861_ASUS_LAPTOP] = {
15728 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15729 .init_verbs = { alc861_asus_init_verbs,
15730 alc861_asus_laptop_init_verbs },
15731 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15732 .dac_nids = alc861_dac_nids,
15733 .dig_out_nid = ALC861_DIGOUT_NID,
15734 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15735 .channel_mode = alc883_3ST_2ch_modes,
15736 .need_dac_fix = 1,
15737 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15738 .adc_nids = alc861_adc_nids,
15739 .input_mux = &alc861_capture_source,
15740 },
15741};
Kailang Yangdf694da2005-12-05 19:42:22 +010015742
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015743/* Pin config fixes */
15744enum {
15745 PINFIX_FSC_AMILO_PI1505,
15746};
15747
15748static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
15749 { 0x0b, 0x0221101f }, /* HP */
15750 { 0x0f, 0x90170310 }, /* speaker */
15751 { }
15752};
15753
15754static const struct alc_fixup alc861_fixups[] = {
15755 [PINFIX_FSC_AMILO_PI1505] = {
15756 .pins = alc861_fsc_amilo_pi1505_pinfix
15757 },
15758};
15759
15760static struct snd_pci_quirk alc861_fixup_tbl[] = {
15761 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15762 {}
15763};
Kailang Yangdf694da2005-12-05 19:42:22 +010015764
15765static int patch_alc861(struct hda_codec *codec)
15766{
15767 struct alc_spec *spec;
15768 int board_config;
15769 int err;
15770
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015771 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015772 if (spec == NULL)
15773 return -ENOMEM;
15774
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015775 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015776
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015777 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15778 alc861_models,
15779 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015780
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015781 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015782 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15783 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015784 board_config = ALC861_AUTO;
15785 }
15786
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015787 if (board_config == ALC861_AUTO)
15788 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015789
Kailang Yangdf694da2005-12-05 19:42:22 +010015790 if (board_config == ALC861_AUTO) {
15791 /* automatic parse from the BIOS config */
15792 err = alc861_parse_auto_config(codec);
15793 if (err < 0) {
15794 alc_free(codec);
15795 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015796 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015797 printk(KERN_INFO
15798 "hda_codec: Cannot set up configuration "
15799 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015800 board_config = ALC861_3ST_DIG;
15801 }
15802 }
15803
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015804 err = snd_hda_attach_beep_device(codec, 0x23);
15805 if (err < 0) {
15806 alc_free(codec);
15807 return err;
15808 }
15809
Kailang Yangdf694da2005-12-05 19:42:22 +010015810 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015811 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015812
Kailang Yangdf694da2005-12-05 19:42:22 +010015813 spec->stream_analog_playback = &alc861_pcm_analog_playback;
15814 spec->stream_analog_capture = &alc861_pcm_analog_capture;
15815
Kailang Yangdf694da2005-12-05 19:42:22 +010015816 spec->stream_digital_playback = &alc861_pcm_digital_playback;
15817 spec->stream_digital_capture = &alc861_pcm_digital_capture;
15818
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015819 if (!spec->cap_mixer)
15820 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015821 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15822
Takashi Iwai2134ea42008-01-10 16:53:55 +010015823 spec->vmaster_nid = 0x03;
15824
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015825 if (board_config == ALC861_AUTO)
15826 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
15827
Kailang Yangdf694da2005-12-05 19:42:22 +010015828 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015829 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015830 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015831#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015832 spec->power_hook = alc_power_eapd;
15833#endif
15834 }
15835#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015836 if (!spec->loopback.amplist)
15837 spec->loopback.amplist = alc861_loopbacks;
15838#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015839
Kailang Yangdf694da2005-12-05 19:42:22 +010015840 return 0;
15841}
15842
15843/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015844 * ALC861-VD support
15845 *
15846 * Based on ALC882
15847 *
15848 * In addition, an independent DAC
15849 */
15850#define ALC861VD_DIGOUT_NID 0x06
15851
15852static hda_nid_t alc861vd_dac_nids[4] = {
15853 /* front, surr, clfe, side surr */
15854 0x02, 0x03, 0x04, 0x05
15855};
15856
15857/* dac_nids for ALC660vd are in a different order - according to
15858 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015859 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015860 * of ALC660vd codecs, but for now there is only 3stack mixer
15861 * - and it is the same as in 861vd.
15862 * adc_nids in ALC660vd are (is) the same as in 861vd
15863 */
15864static hda_nid_t alc660vd_dac_nids[3] = {
15865 /* front, rear, clfe, rear_surr */
15866 0x02, 0x04, 0x03
15867};
15868
15869static hda_nid_t alc861vd_adc_nids[1] = {
15870 /* ADC0 */
15871 0x09,
15872};
15873
Takashi Iwaie1406342008-02-11 18:32:32 +010015874static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15875
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015876/* input MUX */
15877/* FIXME: should be a matrix-type input source selection */
15878static struct hda_input_mux alc861vd_capture_source = {
15879 .num_items = 4,
15880 .items = {
15881 { "Mic", 0x0 },
15882 { "Front Mic", 0x1 },
15883 { "Line", 0x2 },
15884 { "CD", 0x4 },
15885 },
15886};
15887
Kailang Yang272a5272007-05-14 11:00:38 +020015888static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015889 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015890 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015891 { "Ext Mic", 0x0 },
15892 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015893 },
15894};
15895
Kailang Yangd1a991a2007-08-15 16:21:59 +020015896static struct hda_input_mux alc861vd_hp_capture_source = {
15897 .num_items = 2,
15898 .items = {
15899 { "Front Mic", 0x0 },
15900 { "ATAPI Mic", 0x1 },
15901 },
15902};
15903
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015904/*
15905 * 2ch mode
15906 */
15907static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15908 { 2, NULL }
15909};
15910
15911/*
15912 * 6ch mode
15913 */
15914static struct hda_verb alc861vd_6stack_ch6_init[] = {
15915 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15916 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15917 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15918 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15919 { } /* end */
15920};
15921
15922/*
15923 * 8ch mode
15924 */
15925static struct hda_verb alc861vd_6stack_ch8_init[] = {
15926 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15927 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15928 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15929 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15930 { } /* end */
15931};
15932
15933static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15934 { 6, alc861vd_6stack_ch6_init },
15935 { 8, alc861vd_6stack_ch8_init },
15936};
15937
15938static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15939 {
15940 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15941 .name = "Channel Mode",
15942 .info = alc_ch_mode_info,
15943 .get = alc_ch_mode_get,
15944 .put = alc_ch_mode_put,
15945 },
15946 { } /* end */
15947};
15948
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015949/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15950 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15951 */
15952static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15953 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15954 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15955
15956 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15957 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15958
15959 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15960 HDA_OUTPUT),
15961 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15962 HDA_OUTPUT),
15963 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15964 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15965
15966 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15967 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15968
15969 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15970
15971 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15972 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15973 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15974
15975 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15976 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15977 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15978
15979 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15980 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15981
15982 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15983 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15984
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015985 { } /* end */
15986};
15987
15988static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15989 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15990 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15991
15992 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15993
15994 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15995 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15996 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15997
15998 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15999 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16000 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16001
16002 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16003 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16004
16005 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16006 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16007
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016008 { } /* end */
16009};
16010
Kailang Yangbdd148a2007-05-08 15:19:08 +020016011static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16012 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16013 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16014 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16015
16016 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16017
16018 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
16019 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16020 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16021
16022 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
16023 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16024 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16025
16026 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16027 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16028
16029 { } /* end */
16030};
16031
Tobin Davisb419f342008-03-07 11:57:51 +010016032/* Pin assignment: Speaker=0x14, HP = 0x15,
16033 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016034 */
16035static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016036 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16037 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016038 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16039 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010016040 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
16041 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16042 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16043 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
16044 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16045 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016046 { } /* end */
16047};
16048
Kailang Yangd1a991a2007-08-15 16:21:59 +020016049/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16050 * Front Mic=0x18, ATAPI Mic = 0x19,
16051 */
16052static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16053 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16054 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16055 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16056 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16057 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16058 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16059 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16060 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016061
Kailang Yangd1a991a2007-08-15 16:21:59 +020016062 { } /* end */
16063};
16064
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016065/*
16066 * generic initialization of ADC, input mixers and output mixers
16067 */
16068static struct hda_verb alc861vd_volume_init_verbs[] = {
16069 /*
16070 * Unmute ADC0 and set the default input to mic-in
16071 */
16072 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16073 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16074
16075 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16076 * the analog-loopback mixer widget
16077 */
16078 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016079 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16080 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16081 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16082 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16083 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016084
16085 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16087 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16088 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016089 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016090
16091 /*
16092 * Set up output mixers (0x02 - 0x05)
16093 */
16094 /* set vol=0 to output mixers */
16095 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16096 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16097 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16098 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16099
16100 /* set up input amps for analog loopback */
16101 /* Amp Indices: DAC = 0, mixer = 1 */
16102 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16103 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16104 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16105 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16106 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16107 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16108 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16109 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16110
16111 { }
16112};
16113
16114/*
16115 * 3-stack pin configuration:
16116 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16117 */
16118static struct hda_verb alc861vd_3stack_init_verbs[] = {
16119 /*
16120 * Set pin mode and muting
16121 */
16122 /* set front pin widgets 0x14 for output */
16123 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16124 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16125 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16126
16127 /* Mic (rear) pin: input vref at 80% */
16128 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16129 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16130 /* Front Mic pin: input vref at 80% */
16131 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16132 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16133 /* Line In pin: input */
16134 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16135 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16136 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16137 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16138 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16139 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16140 /* CD pin widget for input */
16141 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16142
16143 { }
16144};
16145
16146/*
16147 * 6-stack pin configuration:
16148 */
16149static struct hda_verb alc861vd_6stack_init_verbs[] = {
16150 /*
16151 * Set pin mode and muting
16152 */
16153 /* set front pin widgets 0x14 for output */
16154 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16155 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16156 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16157
16158 /* Rear Pin: output 1 (0x0d) */
16159 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16160 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16161 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16162 /* CLFE Pin: output 2 (0x0e) */
16163 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16164 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16165 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16166 /* Side Pin: output 3 (0x0f) */
16167 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16168 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16169 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16170
16171 /* Mic (rear) pin: input vref at 80% */
16172 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16173 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16174 /* Front Mic pin: input vref at 80% */
16175 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16176 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16177 /* Line In pin: input */
16178 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16179 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16180 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16181 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16182 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16183 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16184 /* CD pin widget for input */
16185 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16186
16187 { }
16188};
16189
Kailang Yangbdd148a2007-05-08 15:19:08 +020016190static struct hda_verb alc861vd_eapd_verbs[] = {
16191 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16192 { }
16193};
16194
Kailang Yangf9423e72008-05-27 12:32:25 +020016195static struct hda_verb alc660vd_eapd_verbs[] = {
16196 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16197 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16198 { }
16199};
16200
Kailang Yangbdd148a2007-05-08 15:19:08 +020016201static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16202 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16203 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16204 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16205 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016206 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016207 {}
16208};
16209
Kailang Yangbdd148a2007-05-08 15:19:08 +020016210static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
16211{
16212 unsigned int present;
16213 unsigned char bits;
16214
Wu Fengguang864f92b2009-11-18 12:38:02 +080016215 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016216 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016217
Takashi Iwai47fd8302007-08-10 17:11:07 +020016218 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
16219 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016220}
16221
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016222static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016223{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016224 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016225 spec->autocfg.hp_pins[0] = 0x1b;
16226 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016227}
16228
16229static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16230{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016231 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016232 alc861vd_lenovo_mic_automute(codec);
16233}
16234
16235static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16236 unsigned int res)
16237{
16238 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016239 case ALC880_MIC_EVENT:
16240 alc861vd_lenovo_mic_automute(codec);
16241 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016242 default:
16243 alc_automute_amp_unsol_event(codec, res);
16244 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016245 }
16246}
16247
Kailang Yang272a5272007-05-14 11:00:38 +020016248static struct hda_verb alc861vd_dallas_verbs[] = {
16249 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16250 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16251 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16252 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16253
16254 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16255 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16256 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16257 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16258 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16259 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16260 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16261 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016262
Kailang Yang272a5272007-05-14 11:00:38 +020016263 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16264 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16265 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16266 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16267 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16268 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16269 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16270 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16271
16272 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16273 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16274 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16275 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16276 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16277 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16278 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16279 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16280
16281 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16282 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16283 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16284 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16285
16286 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016287 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016288 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16289
16290 { } /* end */
16291};
16292
16293/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016294static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016295{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016296 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016297
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016298 spec->autocfg.hp_pins[0] = 0x15;
16299 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016300}
16301
Takashi Iwaicb53c622007-08-10 17:21:45 +020016302#ifdef CONFIG_SND_HDA_POWER_SAVE
16303#define alc861vd_loopbacks alc880_loopbacks
16304#endif
16305
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016306/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016307#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16308#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16309#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16310#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16311
16312/*
16313 * configuration and preset
16314 */
16315static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16316 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016317 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016318 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016319 [ALC861VD_3ST] = "3stack",
16320 [ALC861VD_3ST_DIG] = "3stack-digout",
16321 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016322 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016323 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016324 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016325 [ALC861VD_AUTO] = "auto",
16326};
16327
16328static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016329 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16330 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016331 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016332 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016333 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016334 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016335 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016336 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016337 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016338 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016339 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016340 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016341 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016342 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016343 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016344 {}
16345};
16346
16347static struct alc_config_preset alc861vd_presets[] = {
16348 [ALC660VD_3ST] = {
16349 .mixers = { alc861vd_3st_mixer },
16350 .init_verbs = { alc861vd_volume_init_verbs,
16351 alc861vd_3stack_init_verbs },
16352 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16353 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016354 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16355 .channel_mode = alc861vd_3stack_2ch_modes,
16356 .input_mux = &alc861vd_capture_source,
16357 },
Mike Crash6963f842007-06-25 12:12:51 +020016358 [ALC660VD_3ST_DIG] = {
16359 .mixers = { alc861vd_3st_mixer },
16360 .init_verbs = { alc861vd_volume_init_verbs,
16361 alc861vd_3stack_init_verbs },
16362 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16363 .dac_nids = alc660vd_dac_nids,
16364 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016365 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16366 .channel_mode = alc861vd_3stack_2ch_modes,
16367 .input_mux = &alc861vd_capture_source,
16368 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016369 [ALC861VD_3ST] = {
16370 .mixers = { alc861vd_3st_mixer },
16371 .init_verbs = { alc861vd_volume_init_verbs,
16372 alc861vd_3stack_init_verbs },
16373 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16374 .dac_nids = alc861vd_dac_nids,
16375 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16376 .channel_mode = alc861vd_3stack_2ch_modes,
16377 .input_mux = &alc861vd_capture_source,
16378 },
16379 [ALC861VD_3ST_DIG] = {
16380 .mixers = { alc861vd_3st_mixer },
16381 .init_verbs = { alc861vd_volume_init_verbs,
16382 alc861vd_3stack_init_verbs },
16383 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16384 .dac_nids = alc861vd_dac_nids,
16385 .dig_out_nid = ALC861VD_DIGOUT_NID,
16386 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16387 .channel_mode = alc861vd_3stack_2ch_modes,
16388 .input_mux = &alc861vd_capture_source,
16389 },
16390 [ALC861VD_6ST_DIG] = {
16391 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16392 .init_verbs = { alc861vd_volume_init_verbs,
16393 alc861vd_6stack_init_verbs },
16394 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16395 .dac_nids = alc861vd_dac_nids,
16396 .dig_out_nid = ALC861VD_DIGOUT_NID,
16397 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16398 .channel_mode = alc861vd_6stack_modes,
16399 .input_mux = &alc861vd_capture_source,
16400 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016401 [ALC861VD_LENOVO] = {
16402 .mixers = { alc861vd_lenovo_mixer },
16403 .init_verbs = { alc861vd_volume_init_verbs,
16404 alc861vd_3stack_init_verbs,
16405 alc861vd_eapd_verbs,
16406 alc861vd_lenovo_unsol_verbs },
16407 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16408 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016409 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16410 .channel_mode = alc861vd_3stack_2ch_modes,
16411 .input_mux = &alc861vd_capture_source,
16412 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016413 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016414 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016415 },
Kailang Yang272a5272007-05-14 11:00:38 +020016416 [ALC861VD_DALLAS] = {
16417 .mixers = { alc861vd_dallas_mixer },
16418 .init_verbs = { alc861vd_dallas_verbs },
16419 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16420 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016421 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16422 .channel_mode = alc861vd_3stack_2ch_modes,
16423 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016424 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016425 .setup = alc861vd_dallas_setup,
16426 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016427 },
16428 [ALC861VD_HP] = {
16429 .mixers = { alc861vd_hp_mixer },
16430 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16431 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16432 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016433 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016434 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16435 .channel_mode = alc861vd_3stack_2ch_modes,
16436 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016437 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016438 .setup = alc861vd_dallas_setup,
16439 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016440 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016441 [ALC660VD_ASUS_V1S] = {
16442 .mixers = { alc861vd_lenovo_mixer },
16443 .init_verbs = { alc861vd_volume_init_verbs,
16444 alc861vd_3stack_init_verbs,
16445 alc861vd_eapd_verbs,
16446 alc861vd_lenovo_unsol_verbs },
16447 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16448 .dac_nids = alc660vd_dac_nids,
16449 .dig_out_nid = ALC861VD_DIGOUT_NID,
16450 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16451 .channel_mode = alc861vd_3stack_2ch_modes,
16452 .input_mux = &alc861vd_capture_source,
16453 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016454 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016455 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016456 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016457};
16458
16459/*
16460 * BIOS auto configuration
16461 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016462static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16463 const struct auto_pin_cfg *cfg)
16464{
Kailang Yang6227cdc2010-02-25 08:36:52 +010016465 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016466}
16467
16468
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016469static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16470 hda_nid_t nid, int pin_type, int dac_idx)
16471{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016472 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016473}
16474
16475static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16476{
16477 struct alc_spec *spec = codec->spec;
16478 int i;
16479
16480 for (i = 0; i <= HDA_SIDE; i++) {
16481 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016482 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016483 if (nid)
16484 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016485 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016486 }
16487}
16488
16489
16490static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16491{
16492 struct alc_spec *spec = codec->spec;
16493 hda_nid_t pin;
16494
16495 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016496 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016497 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016498 pin = spec->autocfg.speaker_pins[0];
16499 if (pin)
16500 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016501}
16502
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016503#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
16504
16505static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
16506{
16507 struct alc_spec *spec = codec->spec;
16508 int i;
16509
16510 for (i = 0; i < AUTO_PIN_LAST; i++) {
16511 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020016512 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016513 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010016514 if (nid != ALC861VD_PIN_CD_NID &&
16515 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016516 snd_hda_codec_write(codec, nid, 0,
16517 AC_VERB_SET_AMP_GAIN_MUTE,
16518 AMP_OUT_MUTE);
16519 }
16520 }
16521}
16522
Takashi Iwaif511b012008-08-15 16:46:42 +020016523#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16524
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016525#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16526#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16527
16528/* add playback controls from the parsed DAC table */
16529/* Based on ALC880 version. But ALC861VD has separate,
16530 * different NIDs for mute/unmute switch and volume control */
16531static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16532 const struct auto_pin_cfg *cfg)
16533{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016534 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
16535 hda_nid_t nid_v, nid_s;
16536 int i, err;
16537
16538 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016539 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016540 continue;
16541 nid_v = alc861vd_idx_to_mixer_vol(
16542 alc880_dac_to_idx(
16543 spec->multiout.dac_nids[i]));
16544 nid_s = alc861vd_idx_to_mixer_switch(
16545 alc880_dac_to_idx(
16546 spec->multiout.dac_nids[i]));
16547
16548 if (i == 2) {
16549 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016550 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16551 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016552 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16553 HDA_OUTPUT));
16554 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016555 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016556 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16557 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016558 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16559 HDA_OUTPUT));
16560 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016561 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016562 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16563 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016564 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16565 HDA_INPUT));
16566 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016567 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016568 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16569 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016570 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16571 HDA_INPUT));
16572 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016573 return err;
16574 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016575 const char *pfx;
16576 if (cfg->line_outs == 1 &&
16577 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
16578 if (!cfg->hp_pins)
16579 pfx = "Speaker";
16580 else
16581 pfx = "PCM";
16582 } else
16583 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016584 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016585 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16586 HDA_OUTPUT));
16587 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016588 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020016589 if (cfg->line_outs == 1 &&
16590 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
16591 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016592 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016593 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016594 HDA_INPUT));
16595 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016596 return err;
16597 }
16598 }
16599 return 0;
16600}
16601
16602/* add playback controls for speaker and HP outputs */
16603/* Based on ALC880 version. But ALC861VD has separate,
16604 * different NIDs for mute/unmute switch and volume control */
16605static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16606 hda_nid_t pin, const char *pfx)
16607{
16608 hda_nid_t nid_v, nid_s;
16609 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016610
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016611 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016612 return 0;
16613
16614 if (alc880_is_fixed_pin(pin)) {
16615 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16616 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016617 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016618 spec->multiout.hp_nid = nid_v;
16619 else
16620 spec->multiout.extra_out_nid[0] = nid_v;
16621 /* control HP volume/switch on the output mixer amp */
16622 nid_v = alc861vd_idx_to_mixer_vol(
16623 alc880_fixed_pin_idx(pin));
16624 nid_s = alc861vd_idx_to_mixer_switch(
16625 alc880_fixed_pin_idx(pin));
16626
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016627 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016628 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16629 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016630 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016631 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016632 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16633 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016634 return err;
16635 } else if (alc880_is_multi_pin(pin)) {
16636 /* set manual connection */
16637 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016638 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016639 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16640 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016641 return err;
16642 }
16643 return 0;
16644}
16645
16646/* parse the BIOS configuration and set up the alc_spec
16647 * return 1 if successful, 0 if the proper config is not found,
16648 * or a negative error code
16649 * Based on ALC880 version - had to change it to override
16650 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16651static int alc861vd_parse_auto_config(struct hda_codec *codec)
16652{
16653 struct alc_spec *spec = codec->spec;
16654 int err;
16655 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
16656
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016657 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16658 alc861vd_ignore);
16659 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016660 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016661 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016662 return 0; /* can't find valid BIOS pin config */
16663
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016664 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16665 if (err < 0)
16666 return err;
16667 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16668 if (err < 0)
16669 return err;
16670 err = alc861vd_auto_create_extra_out(spec,
16671 spec->autocfg.speaker_pins[0],
16672 "Speaker");
16673 if (err < 0)
16674 return err;
16675 err = alc861vd_auto_create_extra_out(spec,
16676 spec->autocfg.hp_pins[0],
16677 "Headphone");
16678 if (err < 0)
16679 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016680 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016681 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016682 return err;
16683
16684 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16685
Takashi Iwai757899a2010-07-30 10:48:14 +020016686 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016687
Takashi Iwai603c4012008-07-30 15:01:44 +020016688 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016689 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016690
Takashi Iwaid88897e2008-10-31 15:01:37 +010016691 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016692
16693 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016694 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016695
Takashi Iwai776e1842007-08-29 15:07:11 +020016696 err = alc_auto_add_mic_boost(codec);
16697 if (err < 0)
16698 return err;
16699
Kailang Yang6227cdc2010-02-25 08:36:52 +010016700 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016701
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016702 return 1;
16703}
16704
16705/* additional initialization for auto-configuration model */
16706static void alc861vd_auto_init(struct hda_codec *codec)
16707{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016708 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016709 alc861vd_auto_init_multi_out(codec);
16710 alc861vd_auto_init_hp_out(codec);
16711 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016712 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016713 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016714 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016715 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016716}
16717
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016718enum {
16719 ALC660VD_FIX_ASUS_GPIO1
16720};
16721
16722/* reset GPIO1 */
16723static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
16724 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16725 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16726 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16727 { }
16728};
16729
16730static const struct alc_fixup alc861vd_fixups[] = {
16731 [ALC660VD_FIX_ASUS_GPIO1] = {
16732 .verbs = alc660vd_fix_asus_gpio1_verbs,
16733 },
16734};
16735
16736static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
16737 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16738 {}
16739};
16740
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016741static int patch_alc861vd(struct hda_codec *codec)
16742{
16743 struct alc_spec *spec;
16744 int err, board_config;
16745
16746 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16747 if (spec == NULL)
16748 return -ENOMEM;
16749
16750 codec->spec = spec;
16751
16752 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16753 alc861vd_models,
16754 alc861vd_cfg_tbl);
16755
16756 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016757 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16758 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016759 board_config = ALC861VD_AUTO;
16760 }
16761
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016762 if (board_config == ALC861VD_AUTO)
16763 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016764
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016765 if (board_config == ALC861VD_AUTO) {
16766 /* automatic parse from the BIOS config */
16767 err = alc861vd_parse_auto_config(codec);
16768 if (err < 0) {
16769 alc_free(codec);
16770 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016771 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016772 printk(KERN_INFO
16773 "hda_codec: Cannot set up configuration "
16774 "from BIOS. Using base mode...\n");
16775 board_config = ALC861VD_3ST;
16776 }
16777 }
16778
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016779 err = snd_hda_attach_beep_device(codec, 0x23);
16780 if (err < 0) {
16781 alc_free(codec);
16782 return err;
16783 }
16784
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016785 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016786 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016787
Kailang Yang2f893282008-05-27 12:14:47 +020016788 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016789 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016790 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016791 }
16792
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016793 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16794 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16795
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016796 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16797 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16798
Takashi Iwaidd704692009-08-11 08:45:11 +020016799 if (!spec->adc_nids) {
16800 spec->adc_nids = alc861vd_adc_nids;
16801 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16802 }
16803 if (!spec->capsrc_nids)
16804 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016805
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016806 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016807 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016808
Takashi Iwai2134ea42008-01-10 16:53:55 +010016809 spec->vmaster_nid = 0x02;
16810
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016811 if (board_config == ALC861VD_AUTO)
16812 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
16813
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016814 codec->patch_ops = alc_patch_ops;
16815
16816 if (board_config == ALC861VD_AUTO)
16817 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016818#ifdef CONFIG_SND_HDA_POWER_SAVE
16819 if (!spec->loopback.amplist)
16820 spec->loopback.amplist = alc861vd_loopbacks;
16821#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016822
16823 return 0;
16824}
16825
16826/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016827 * ALC662 support
16828 *
16829 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16830 * configuration. Each pin widget can choose any input DACs and a mixer.
16831 * Each ADC is connected from a mixer of all inputs. This makes possible
16832 * 6-channel independent captures.
16833 *
16834 * In addition, an independent DAC for the multi-playback (not used in this
16835 * driver yet).
16836 */
16837#define ALC662_DIGOUT_NID 0x06
16838#define ALC662_DIGIN_NID 0x0a
16839
16840static hda_nid_t alc662_dac_nids[4] = {
16841 /* front, rear, clfe, rear_surr */
16842 0x02, 0x03, 0x04
16843};
16844
Kailang Yang622e84c2009-04-21 07:39:04 +020016845static hda_nid_t alc272_dac_nids[2] = {
16846 0x02, 0x03
16847};
16848
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016849static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016850 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016851 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016852};
Takashi Iwaie1406342008-02-11 18:32:32 +010016853
Kailang Yang622e84c2009-04-21 07:39:04 +020016854static hda_nid_t alc272_adc_nids[1] = {
16855 /* ADC1-2 */
16856 0x08,
16857};
16858
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016859static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016860static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16861
Takashi Iwaie1406342008-02-11 18:32:32 +010016862
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016863/* input MUX */
16864/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016865static struct hda_input_mux alc662_capture_source = {
16866 .num_items = 4,
16867 .items = {
16868 { "Mic", 0x0 },
16869 { "Front Mic", 0x1 },
16870 { "Line", 0x2 },
16871 { "CD", 0x4 },
16872 },
16873};
16874
16875static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16876 .num_items = 2,
16877 .items = {
16878 { "Mic", 0x1 },
16879 { "Line", 0x2 },
16880 },
16881};
Kailang Yang291702f2007-10-16 14:28:03 +020016882
Kailang Yang6dda9f42008-05-27 12:05:31 +020016883static struct hda_input_mux alc663_capture_source = {
16884 .num_items = 3,
16885 .items = {
16886 { "Mic", 0x0 },
16887 { "Front Mic", 0x1 },
16888 { "Line", 0x2 },
16889 },
16890};
16891
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016892#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016893static struct hda_input_mux alc272_nc10_capture_source = {
16894 .num_items = 16,
16895 .items = {
16896 { "Autoselect Mic", 0x0 },
16897 { "Internal Mic", 0x1 },
16898 { "In-0x02", 0x2 },
16899 { "In-0x03", 0x3 },
16900 { "In-0x04", 0x4 },
16901 { "In-0x05", 0x5 },
16902 { "In-0x06", 0x6 },
16903 { "In-0x07", 0x7 },
16904 { "In-0x08", 0x8 },
16905 { "In-0x09", 0x9 },
16906 { "In-0x0a", 0x0a },
16907 { "In-0x0b", 0x0b },
16908 { "In-0x0c", 0x0c },
16909 { "In-0x0d", 0x0d },
16910 { "In-0x0e", 0x0e },
16911 { "In-0x0f", 0x0f },
16912 },
16913};
16914#endif
16915
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016916/*
16917 * 2ch mode
16918 */
16919static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16920 { 2, NULL }
16921};
16922
16923/*
16924 * 2ch mode
16925 */
16926static struct hda_verb alc662_3ST_ch2_init[] = {
16927 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16928 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16929 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16930 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16931 { } /* end */
16932};
16933
16934/*
16935 * 6ch mode
16936 */
16937static struct hda_verb alc662_3ST_ch6_init[] = {
16938 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16939 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16940 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16941 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16942 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16943 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16944 { } /* end */
16945};
16946
16947static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16948 { 2, alc662_3ST_ch2_init },
16949 { 6, alc662_3ST_ch6_init },
16950};
16951
16952/*
16953 * 2ch mode
16954 */
16955static struct hda_verb alc662_sixstack_ch6_init[] = {
16956 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16957 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16958 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16959 { } /* end */
16960};
16961
16962/*
16963 * 6ch mode
16964 */
16965static struct hda_verb alc662_sixstack_ch8_init[] = {
16966 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16967 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16968 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16969 { } /* end */
16970};
16971
16972static struct hda_channel_mode alc662_5stack_modes[2] = {
16973 { 2, alc662_sixstack_ch6_init },
16974 { 6, alc662_sixstack_ch8_init },
16975};
16976
16977/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16978 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16979 */
16980
16981static struct snd_kcontrol_new alc662_base_mixer[] = {
16982 /* output mixer control */
16983 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016984 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016985 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016986 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016987 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16988 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016989 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16990 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016991 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16992
16993 /*Input mixer control */
16994 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16995 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16996 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16997 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16998 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16999 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17000 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17001 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017002 { } /* end */
17003};
17004
17005static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17006 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017007 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017008 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17009 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17010 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17011 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17012 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17013 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17014 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17015 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17016 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017017 { } /* end */
17018};
17019
17020static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17021 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017022 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017023 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017024 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017025 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17026 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017027 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17028 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017029 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17030 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17031 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17032 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17033 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17034 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17035 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17036 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17037 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017038 { } /* end */
17039};
17040
17041static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17042 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17043 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017044 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17045 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017046 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17047 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17048 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17049 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17050 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017051 { } /* end */
17052};
17053
Kailang Yang291702f2007-10-16 14:28:03 +020017054static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017055 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17056 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017057
17058 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
17059 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17060 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17061
17062 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17063 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17064 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17065 { } /* end */
17066};
17067
Kailang Yang8c427222008-01-10 13:03:59 +010017068static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017069 ALC262_HIPPO_MASTER_SWITCH,
17070 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017071 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017072 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17073 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017074 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17075 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17076 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17077 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17078 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17079 { } /* end */
17080};
17081
Kailang Yangf1d4e282008-08-26 14:03:29 +020017082static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17083 .ops = &snd_hda_bind_vol,
17084 .values = {
17085 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17086 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17087 0
17088 },
17089};
17090
17091static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17092 .ops = &snd_hda_bind_sw,
17093 .values = {
17094 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17095 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17096 0
17097 },
17098};
17099
Kailang Yang6dda9f42008-05-27 12:05:31 +020017100static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017101 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17102 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17103 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17104 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17105 { } /* end */
17106};
17107
17108static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17109 .ops = &snd_hda_bind_sw,
17110 .values = {
17111 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17112 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17113 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17114 0
17115 },
17116};
17117
17118static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17119 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17120 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17121 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17122 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17123 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17124 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17125
17126 { } /* end */
17127};
17128
17129static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17130 .ops = &snd_hda_bind_sw,
17131 .values = {
17132 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17133 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17134 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17135 0
17136 },
17137};
17138
17139static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17140 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17141 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17142 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17143 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17144 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17145 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17146 { } /* end */
17147};
17148
17149static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017150 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17151 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017152 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17153 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17154 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17155 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17156 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17157 { } /* end */
17158};
17159
17160static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17161 .ops = &snd_hda_bind_vol,
17162 .values = {
17163 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17164 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17165 0
17166 },
17167};
17168
17169static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17170 .ops = &snd_hda_bind_sw,
17171 .values = {
17172 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17173 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17174 0
17175 },
17176};
17177
17178static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17179 HDA_BIND_VOL("Master Playback Volume",
17180 &alc663_asus_two_bind_master_vol),
17181 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17182 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017183 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17184 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17185 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017186 { } /* end */
17187};
17188
17189static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17190 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17191 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17192 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17193 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17194 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17195 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017196 { } /* end */
17197};
17198
17199static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17200 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17201 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17202 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17203 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17204 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17205
17206 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17207 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17208 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17209 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17210 { } /* end */
17211};
17212
17213static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17214 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17215 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17216 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17217
17218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17220 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17221 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17222 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17223 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17224 { } /* end */
17225};
17226
Kailang Yangebb83ee2009-12-17 12:23:00 +010017227static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17228 .ops = &snd_hda_bind_sw,
17229 .values = {
17230 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17231 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17232 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17233 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17234 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17235 0
17236 },
17237};
17238
17239static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17240 .ops = &snd_hda_bind_sw,
17241 .values = {
17242 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17243 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17244 0
17245 },
17246};
17247
17248static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17249 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17250 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17251 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17252 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17253 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17254 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17255 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17256 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17257 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17258 { } /* end */
17259};
17260
17261static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17262 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17263 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17264 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17265 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17266 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17267 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17268 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17269 { } /* end */
17270};
17271
17272
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017273static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17274 {
17275 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17276 .name = "Channel Mode",
17277 .info = alc_ch_mode_info,
17278 .get = alc_ch_mode_get,
17279 .put = alc_ch_mode_put,
17280 },
17281 { } /* end */
17282};
17283
17284static struct hda_verb alc662_init_verbs[] = {
17285 /* ADC: mute amp left and right */
17286 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17287 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017288
Kailang Yangb60dd392007-09-20 12:50:29 +020017289 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17290 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17291 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17292 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17293 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17294 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017295
17296 /* Front Pin: output 0 (0x0c) */
17297 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17298 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17299
17300 /* Rear Pin: output 1 (0x0d) */
17301 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17302 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17303
17304 /* CLFE Pin: output 2 (0x0e) */
17305 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17306 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17307
17308 /* Mic (rear) pin: input vref at 80% */
17309 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17310 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17311 /* Front Mic pin: input vref at 80% */
17312 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17313 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17314 /* Line In pin: input */
17315 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17316 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17317 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17318 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17319 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17320 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17321 /* CD pin widget for input */
17322 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17323
17324 /* FIXME: use matrix-type input source selection */
17325 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17326 /* Input mixer */
17327 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017328 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017329
17330 /* always trun on EAPD */
17331 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17332 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17333
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017334 { }
17335};
17336
Kailang Yangcec27c82010-02-04 14:18:18 +010017337static struct hda_verb alc663_init_verbs[] = {
17338 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17339 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17340 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17341 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17342 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17343 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17344 { }
17345};
17346
17347static struct hda_verb alc272_init_verbs[] = {
17348 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17349 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17350 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17351 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17352 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17353 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17354 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17355 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17356 { }
17357};
17358
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017359static struct hda_verb alc662_sue_init_verbs[] = {
17360 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17361 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017362 {}
17363};
17364
17365static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17366 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17367 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17368 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017369};
17370
Kailang Yang8c427222008-01-10 13:03:59 +010017371/* Set Unsolicited Event*/
17372static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17373 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17374 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17375 {}
17376};
17377
Kailang Yang6dda9f42008-05-27 12:05:31 +020017378static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017379 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17380 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017381 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17382 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017383 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17384 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017386 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17387 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17388 {}
17389};
17390
Kailang Yangf1d4e282008-08-26 14:03:29 +020017391static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17392 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17393 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17394 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17395 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17396 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17397 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17398 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17399 {}
17400};
17401
17402static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17403 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17404 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17405 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17406 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17407 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17408 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17409 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17410 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17411 {}
17412};
17413
17414static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17415 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17416 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17417 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17418 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17419 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17420 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17421 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17422 {}
17423};
17424
17425static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17426 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17427 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17428 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17429 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17430 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17431 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17432 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17433 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17434 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17435 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17436 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17437 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17438 {}
17439};
17440
17441static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17442 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17443 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17444 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17445 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17446 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17447 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17448 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17449 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17450 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17451 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17452 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17453 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17454 {}
17455};
17456
Kailang Yang6dda9f42008-05-27 12:05:31 +020017457static struct hda_verb alc663_g71v_init_verbs[] = {
17458 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17459 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17460 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17461
17462 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17463 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17464 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17465
17466 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17467 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17468 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17469 {}
17470};
17471
17472static struct hda_verb alc663_g50v_init_verbs[] = {
17473 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17474 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17475 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17476
17477 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17478 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17479 {}
17480};
17481
Kailang Yangf1d4e282008-08-26 14:03:29 +020017482static struct hda_verb alc662_ecs_init_verbs[] = {
17483 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17484 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17485 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17486 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17487 {}
17488};
17489
Kailang Yang622e84c2009-04-21 07:39:04 +020017490static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17491 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17492 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17493 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17494 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17495 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17496 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17497 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17498 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17499 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17500 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17501 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17502 {}
17503};
17504
17505static struct hda_verb alc272_dell_init_verbs[] = {
17506 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17507 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17508 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17509 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17510 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17511 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17512 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17513 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17514 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17515 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17516 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17517 {}
17518};
17519
Kailang Yangebb83ee2009-12-17 12:23:00 +010017520static struct hda_verb alc663_mode7_init_verbs[] = {
17521 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17522 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17523 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17524 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17525 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17526 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17527 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17528 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17529 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17530 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17533 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17534 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17535 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17536 {}
17537};
17538
17539static struct hda_verb alc663_mode8_init_verbs[] = {
17540 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17541 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17542 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17543 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17544 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17545 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17546 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17547 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17548 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17549 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17550 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17551 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17552 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17553 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17554 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17555 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17556 {}
17557};
17558
Kailang Yangf1d4e282008-08-26 14:03:29 +020017559static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
17560 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17561 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17562 { } /* end */
17563};
17564
Kailang Yang622e84c2009-04-21 07:39:04 +020017565static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
17566 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17567 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17568 { } /* end */
17569};
17570
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017571static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
17572{
17573 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017574 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017575
Wu Fengguang864f92b2009-11-18 12:38:02 +080017576 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017577 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017578
Takashi Iwai47fd8302007-08-10 17:11:07 +020017579 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17580 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017581}
17582
17583static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
17584{
17585 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017586 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017587
Wu Fengguang864f92b2009-11-18 12:38:02 +080017588 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020017589 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080017590
Takashi Iwai47fd8302007-08-10 17:11:07 +020017591 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17592 HDA_AMP_MUTE, bits);
17593 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17594 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017595}
17596
17597static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
17598 unsigned int res)
17599{
17600 if ((res >> 26) == ALC880_HP_EVENT)
17601 alc662_lenovo_101e_all_automute(codec);
17602 if ((res >> 26) == ALC880_FRONT_EVENT)
17603 alc662_lenovo_101e_ispeaker_automute(codec);
17604}
17605
Kailang Yang291702f2007-10-16 14:28:03 +020017606/* unsolicited event for HP jack sensing */
17607static void alc662_eeepc_unsol_event(struct hda_codec *codec,
17608 unsigned int res)
17609{
Kailang Yang291702f2007-10-16 14:28:03 +020017610 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017611 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020017612 else
17613 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020017614}
17615
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017616static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017617{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017618 struct alc_spec *spec = codec->spec;
17619
17620 alc262_hippo1_setup(codec);
17621 spec->ext_mic.pin = 0x18;
17622 spec->ext_mic.mux_idx = 0;
17623 spec->int_mic.pin = 0x19;
17624 spec->int_mic.mux_idx = 1;
17625 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017626}
17627
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017628static void alc662_eeepc_inithook(struct hda_codec *codec)
17629{
17630 alc262_hippo_automute(codec);
17631 alc_mic_automute(codec);
17632}
17633
17634static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017635{
Takashi Iwai42171c12009-05-08 14:11:43 +020017636 struct alc_spec *spec = codec->spec;
17637
17638 spec->autocfg.hp_pins[0] = 0x14;
17639 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010017640}
17641
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017642#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
17643
Kailang Yang6dda9f42008-05-27 12:05:31 +020017644static void alc663_m51va_speaker_automute(struct hda_codec *codec)
17645{
17646 unsigned int present;
17647 unsigned char bits;
17648
Wu Fengguang864f92b2009-11-18 12:38:02 +080017649 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017650 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017651 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017652 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017653 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017654 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017655}
17656
17657static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
17658{
17659 unsigned int present;
17660 unsigned char bits;
17661
Wu Fengguang864f92b2009-11-18 12:38:02 +080017662 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017663 bits = present ? HDA_AMP_MUTE : 0;
17664 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017665 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017666 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017667 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017668 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017669 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017670 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017671 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017672}
17673
17674static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
17675{
17676 unsigned int present;
17677 unsigned char bits;
17678
Wu Fengguang864f92b2009-11-18 12:38:02 +080017679 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017680 bits = present ? HDA_AMP_MUTE : 0;
17681 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017682 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017683 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017684 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017685 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017686 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017687 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017688 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017689}
17690
17691static void alc662_f5z_speaker_automute(struct hda_codec *codec)
17692{
17693 unsigned int present;
17694 unsigned char bits;
17695
Wu Fengguang864f92b2009-11-18 12:38:02 +080017696 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017697 bits = present ? 0 : PIN_OUT;
17698 snd_hda_codec_write(codec, 0x14, 0,
17699 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
17700}
17701
17702static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
17703{
17704 unsigned int present1, present2;
17705
Wu Fengguang864f92b2009-11-18 12:38:02 +080017706 present1 = snd_hda_jack_detect(codec, 0x21);
17707 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017708
17709 if (present1 || present2) {
17710 snd_hda_codec_write_cache(codec, 0x14, 0,
17711 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17712 } else {
17713 snd_hda_codec_write_cache(codec, 0x14, 0,
17714 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17715 }
17716}
17717
17718static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
17719{
17720 unsigned int present1, present2;
17721
Wu Fengguang864f92b2009-11-18 12:38:02 +080017722 present1 = snd_hda_jack_detect(codec, 0x1b);
17723 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017724
17725 if (present1 || present2) {
17726 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017727 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017728 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017729 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017730 } else {
17731 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020017732 HDA_AMP_MUTE, 0);
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, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017735 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020017736}
17737
Kailang Yangebb83ee2009-12-17 12:23:00 +010017738static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
17739{
17740 unsigned int present1, present2;
17741
17742 present1 = snd_hda_codec_read(codec, 0x1b, 0,
17743 AC_VERB_GET_PIN_SENSE, 0)
17744 & AC_PINSENSE_PRESENCE;
17745 present2 = snd_hda_codec_read(codec, 0x21, 0,
17746 AC_VERB_GET_PIN_SENSE, 0)
17747 & AC_PINSENSE_PRESENCE;
17748
17749 if (present1 || present2) {
17750 snd_hda_codec_write_cache(codec, 0x14, 0,
17751 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17752 snd_hda_codec_write_cache(codec, 0x17, 0,
17753 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17754 } else {
17755 snd_hda_codec_write_cache(codec, 0x14, 0,
17756 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17757 snd_hda_codec_write_cache(codec, 0x17, 0,
17758 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17759 }
17760}
17761
17762static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
17763{
17764 unsigned int present1, present2;
17765
17766 present1 = snd_hda_codec_read(codec, 0x21, 0,
17767 AC_VERB_GET_PIN_SENSE, 0)
17768 & AC_PINSENSE_PRESENCE;
17769 present2 = snd_hda_codec_read(codec, 0x15, 0,
17770 AC_VERB_GET_PIN_SENSE, 0)
17771 & AC_PINSENSE_PRESENCE;
17772
17773 if (present1 || present2) {
17774 snd_hda_codec_write_cache(codec, 0x14, 0,
17775 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17776 snd_hda_codec_write_cache(codec, 0x17, 0,
17777 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
17778 } else {
17779 snd_hda_codec_write_cache(codec, 0x14, 0,
17780 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17781 snd_hda_codec_write_cache(codec, 0x17, 0,
17782 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
17783 }
17784}
17785
Kailang Yang6dda9f42008-05-27 12:05:31 +020017786static void alc663_m51va_unsol_event(struct hda_codec *codec,
17787 unsigned int res)
17788{
17789 switch (res >> 26) {
17790 case ALC880_HP_EVENT:
17791 alc663_m51va_speaker_automute(codec);
17792 break;
17793 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017794 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017795 break;
17796 }
17797}
17798
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017799static void alc663_m51va_setup(struct hda_codec *codec)
17800{
17801 struct alc_spec *spec = codec->spec;
17802 spec->ext_mic.pin = 0x18;
17803 spec->ext_mic.mux_idx = 0;
17804 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017805 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017806 spec->auto_mic = 1;
17807}
17808
Kailang Yang6dda9f42008-05-27 12:05:31 +020017809static void alc663_m51va_inithook(struct hda_codec *codec)
17810{
17811 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017812 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017813}
17814
Kailang Yangf1d4e282008-08-26 14:03:29 +020017815/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017816#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017817
17818static void alc663_mode1_setup(struct hda_codec *codec)
17819{
17820 struct alc_spec *spec = codec->spec;
17821 spec->ext_mic.pin = 0x18;
17822 spec->ext_mic.mux_idx = 0;
17823 spec->int_mic.pin = 0x19;
17824 spec->int_mic.mux_idx = 1;
17825 spec->auto_mic = 1;
17826}
17827
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017828#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017829
Kailang Yangf1d4e282008-08-26 14:03:29 +020017830/* ***************** Mode2 ******************************/
17831static void alc662_mode2_unsol_event(struct hda_codec *codec,
17832 unsigned int res)
17833{
17834 switch (res >> 26) {
17835 case ALC880_HP_EVENT:
17836 alc662_f5z_speaker_automute(codec);
17837 break;
17838 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017839 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017840 break;
17841 }
17842}
17843
Kailang Yangebb83ee2009-12-17 12:23:00 +010017844#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017845
Kailang Yangf1d4e282008-08-26 14:03:29 +020017846static void alc662_mode2_inithook(struct hda_codec *codec)
17847{
17848 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017849 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017850}
17851/* ***************** Mode3 ******************************/
17852static void alc663_mode3_unsol_event(struct hda_codec *codec,
17853 unsigned int res)
17854{
17855 switch (res >> 26) {
17856 case ALC880_HP_EVENT:
17857 alc663_two_hp_m1_speaker_automute(codec);
17858 break;
17859 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017860 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017861 break;
17862 }
17863}
17864
Kailang Yangebb83ee2009-12-17 12:23:00 +010017865#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017866
Kailang Yangf1d4e282008-08-26 14:03:29 +020017867static void alc663_mode3_inithook(struct hda_codec *codec)
17868{
17869 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017870 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017871}
17872/* ***************** Mode4 ******************************/
17873static void alc663_mode4_unsol_event(struct hda_codec *codec,
17874 unsigned int res)
17875{
17876 switch (res >> 26) {
17877 case ALC880_HP_EVENT:
17878 alc663_21jd_two_speaker_automute(codec);
17879 break;
17880 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017881 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017882 break;
17883 }
17884}
17885
Kailang Yangebb83ee2009-12-17 12:23:00 +010017886#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017887
Kailang Yangf1d4e282008-08-26 14:03:29 +020017888static void alc663_mode4_inithook(struct hda_codec *codec)
17889{
17890 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017891 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017892}
17893/* ***************** Mode5 ******************************/
17894static void alc663_mode5_unsol_event(struct hda_codec *codec,
17895 unsigned int res)
17896{
17897 switch (res >> 26) {
17898 case ALC880_HP_EVENT:
17899 alc663_15jd_two_speaker_automute(codec);
17900 break;
17901 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017902 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017903 break;
17904 }
17905}
17906
Kailang Yangebb83ee2009-12-17 12:23:00 +010017907#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017908
Kailang Yangf1d4e282008-08-26 14:03:29 +020017909static void alc663_mode5_inithook(struct hda_codec *codec)
17910{
17911 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017912 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017913}
17914/* ***************** Mode6 ******************************/
17915static void alc663_mode6_unsol_event(struct hda_codec *codec,
17916 unsigned int res)
17917{
17918 switch (res >> 26) {
17919 case ALC880_HP_EVENT:
17920 alc663_two_hp_m2_speaker_automute(codec);
17921 break;
17922 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017923 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017924 break;
17925 }
17926}
17927
Kailang Yangebb83ee2009-12-17 12:23:00 +010017928#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017929
Kailang Yangf1d4e282008-08-26 14:03:29 +020017930static void alc663_mode6_inithook(struct hda_codec *codec)
17931{
17932 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017933 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017934}
17935
Kailang Yangebb83ee2009-12-17 12:23:00 +010017936/* ***************** Mode7 ******************************/
17937static void alc663_mode7_unsol_event(struct hda_codec *codec,
17938 unsigned int res)
17939{
17940 switch (res >> 26) {
17941 case ALC880_HP_EVENT:
17942 alc663_two_hp_m7_speaker_automute(codec);
17943 break;
17944 case ALC880_MIC_EVENT:
17945 alc_mic_automute(codec);
17946 break;
17947 }
17948}
17949
17950#define alc663_mode7_setup alc663_mode1_setup
17951
17952static void alc663_mode7_inithook(struct hda_codec *codec)
17953{
17954 alc663_two_hp_m7_speaker_automute(codec);
17955 alc_mic_automute(codec);
17956}
17957
17958/* ***************** Mode8 ******************************/
17959static void alc663_mode8_unsol_event(struct hda_codec *codec,
17960 unsigned int res)
17961{
17962 switch (res >> 26) {
17963 case ALC880_HP_EVENT:
17964 alc663_two_hp_m8_speaker_automute(codec);
17965 break;
17966 case ALC880_MIC_EVENT:
17967 alc_mic_automute(codec);
17968 break;
17969 }
17970}
17971
17972#define alc663_mode8_setup alc663_m51va_setup
17973
17974static void alc663_mode8_inithook(struct hda_codec *codec)
17975{
17976 alc663_two_hp_m8_speaker_automute(codec);
17977 alc_mic_automute(codec);
17978}
17979
Kailang Yang6dda9f42008-05-27 12:05:31 +020017980static void alc663_g71v_hp_automute(struct hda_codec *codec)
17981{
17982 unsigned int present;
17983 unsigned char bits;
17984
Wu Fengguang864f92b2009-11-18 12:38:02 +080017985 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017986 bits = present ? HDA_AMP_MUTE : 0;
17987 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17988 HDA_AMP_MUTE, bits);
17989 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17990 HDA_AMP_MUTE, bits);
17991}
17992
17993static void alc663_g71v_front_automute(struct hda_codec *codec)
17994{
17995 unsigned int present;
17996 unsigned char bits;
17997
Wu Fengguang864f92b2009-11-18 12:38:02 +080017998 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017999 bits = present ? HDA_AMP_MUTE : 0;
18000 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18001 HDA_AMP_MUTE, bits);
18002}
18003
18004static void alc663_g71v_unsol_event(struct hda_codec *codec,
18005 unsigned int res)
18006{
18007 switch (res >> 26) {
18008 case ALC880_HP_EVENT:
18009 alc663_g71v_hp_automute(codec);
18010 break;
18011 case ALC880_FRONT_EVENT:
18012 alc663_g71v_front_automute(codec);
18013 break;
18014 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018015 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018016 break;
18017 }
18018}
18019
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018020#define alc663_g71v_setup alc663_m51va_setup
18021
Kailang Yang6dda9f42008-05-27 12:05:31 +020018022static void alc663_g71v_inithook(struct hda_codec *codec)
18023{
18024 alc663_g71v_front_automute(codec);
18025 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018026 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018027}
18028
18029static void alc663_g50v_unsol_event(struct hda_codec *codec,
18030 unsigned int res)
18031{
18032 switch (res >> 26) {
18033 case ALC880_HP_EVENT:
18034 alc663_m51va_speaker_automute(codec);
18035 break;
18036 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018037 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018038 break;
18039 }
18040}
18041
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018042#define alc663_g50v_setup alc663_m51va_setup
18043
Kailang Yang6dda9f42008-05-27 12:05:31 +020018044static void alc663_g50v_inithook(struct hda_codec *codec)
18045{
18046 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018047 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018048}
18049
Kailang Yangf1d4e282008-08-26 14:03:29 +020018050static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18051 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018052 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018053
18054 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
18055 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18056 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
18057
18058 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
18059 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18060 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18061 { } /* end */
18062};
18063
Chris Pockelé9541ba12009-05-12 08:08:53 +020018064static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18065 /* Master Playback automatically created from Speaker and Headphone */
18066 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18067 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18068 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18069 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18070
18071 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18072 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
18073 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
18074
18075 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18076 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
18077 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
18078 { } /* end */
18079};
18080
Takashi Iwaicb53c622007-08-10 17:21:45 +020018081#ifdef CONFIG_SND_HDA_POWER_SAVE
18082#define alc662_loopbacks alc880_loopbacks
18083#endif
18084
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018085
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018086/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018087#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18088#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18089#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18090#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18091
18092/*
18093 * configuration and preset
18094 */
18095static const char *alc662_models[ALC662_MODEL_LAST] = {
18096 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18097 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18098 [ALC662_3ST_6ch] = "3stack-6ch",
18099 [ALC662_5ST_DIG] = "6stack-dig",
18100 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018101 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018102 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018103 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018104 [ALC663_ASUS_M51VA] = "m51va",
18105 [ALC663_ASUS_G71V] = "g71v",
18106 [ALC663_ASUS_H13] = "h13",
18107 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018108 [ALC663_ASUS_MODE1] = "asus-mode1",
18109 [ALC662_ASUS_MODE2] = "asus-mode2",
18110 [ALC663_ASUS_MODE3] = "asus-mode3",
18111 [ALC663_ASUS_MODE4] = "asus-mode4",
18112 [ALC663_ASUS_MODE5] = "asus-mode5",
18113 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018114 [ALC663_ASUS_MODE7] = "asus-mode7",
18115 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018116 [ALC272_DELL] = "dell",
18117 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018118 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018119 [ALC662_AUTO] = "auto",
18120};
18121
18122static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018123 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018124 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18125 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018126 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18127 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018128 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018129 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18130 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18131 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18132 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018133 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18134 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018135 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018136 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18137 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18138 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18139 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18140 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018141 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018142 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18143 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018144 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18145 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18146 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18147 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018148 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018149 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18150 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18151 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018152 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18153 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18154 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18155 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018156 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018157 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18158 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018159 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018160 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18161 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18162 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018163 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018164 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018165 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18166 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018167 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18168 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18169 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018170 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018171 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18172 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018173 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018174 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018175 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018176 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18177 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18178 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018179 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018180 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18181 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018182 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018183 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018184 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018185 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018186 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18187 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018188 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018189 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018190 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18191 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018192 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018193 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018194 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018195 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018196 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018197 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018198 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18199 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018200 {}
18201};
18202
18203static struct alc_config_preset alc662_presets[] = {
18204 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018205 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018206 .init_verbs = { alc662_init_verbs },
18207 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18208 .dac_nids = alc662_dac_nids,
18209 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018210 .dig_in_nid = ALC662_DIGIN_NID,
18211 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18212 .channel_mode = alc662_3ST_2ch_modes,
18213 .input_mux = &alc662_capture_source,
18214 },
18215 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018216 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018217 .init_verbs = { alc662_init_verbs },
18218 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18219 .dac_nids = alc662_dac_nids,
18220 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018221 .dig_in_nid = ALC662_DIGIN_NID,
18222 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18223 .channel_mode = alc662_3ST_6ch_modes,
18224 .need_dac_fix = 1,
18225 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018226 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018227 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018228 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018229 .init_verbs = { alc662_init_verbs },
18230 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18231 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018232 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18233 .channel_mode = alc662_3ST_6ch_modes,
18234 .need_dac_fix = 1,
18235 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018236 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018237 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018238 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018239 .init_verbs = { alc662_init_verbs },
18240 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18241 .dac_nids = alc662_dac_nids,
18242 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018243 .dig_in_nid = ALC662_DIGIN_NID,
18244 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18245 .channel_mode = alc662_5stack_modes,
18246 .input_mux = &alc662_capture_source,
18247 },
18248 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018249 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018250 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18251 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18252 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018253 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18254 .channel_mode = alc662_3ST_2ch_modes,
18255 .input_mux = &alc662_lenovo_101e_capture_source,
18256 .unsol_event = alc662_lenovo_101e_unsol_event,
18257 .init_hook = alc662_lenovo_101e_all_automute,
18258 },
Kailang Yang291702f2007-10-16 14:28:03 +020018259 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018260 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018261 .init_verbs = { alc662_init_verbs,
18262 alc662_eeepc_sue_init_verbs },
18263 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18264 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018265 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18266 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018267 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018268 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018269 .init_hook = alc662_eeepc_inithook,
18270 },
Kailang Yang8c427222008-01-10 13:03:59 +010018271 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018272 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018273 alc662_chmode_mixer },
18274 .init_verbs = { alc662_init_verbs,
18275 alc662_eeepc_ep20_sue_init_verbs },
18276 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18277 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018278 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18279 .channel_mode = alc662_3ST_6ch_modes,
18280 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018281 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018282 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018283 .init_hook = alc662_eeepc_ep20_inithook,
18284 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018285 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018286 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018287 .init_verbs = { alc662_init_verbs,
18288 alc662_ecs_init_verbs },
18289 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18290 .dac_nids = alc662_dac_nids,
18291 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18292 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018293 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018294 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018295 .init_hook = alc662_eeepc_inithook,
18296 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018297 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018298 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018299 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18300 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18301 .dac_nids = alc662_dac_nids,
18302 .dig_out_nid = ALC662_DIGOUT_NID,
18303 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18304 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018305 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018306 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018307 .init_hook = alc663_m51va_inithook,
18308 },
18309 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018310 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018311 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18312 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18313 .dac_nids = alc662_dac_nids,
18314 .dig_out_nid = ALC662_DIGOUT_NID,
18315 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18316 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018317 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018318 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018319 .init_hook = alc663_g71v_inithook,
18320 },
18321 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018322 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018323 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18324 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18325 .dac_nids = alc662_dac_nids,
18326 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18327 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018328 .unsol_event = alc663_m51va_unsol_event,
18329 .init_hook = alc663_m51va_inithook,
18330 },
18331 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018332 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018333 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18334 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18335 .dac_nids = alc662_dac_nids,
18336 .dig_out_nid = ALC662_DIGOUT_NID,
18337 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18338 .channel_mode = alc662_3ST_6ch_modes,
18339 .input_mux = &alc663_capture_source,
18340 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018341 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018342 .init_hook = alc663_g50v_inithook,
18343 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018344 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018345 .mixers = { alc663_m51va_mixer },
18346 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018347 .init_verbs = { alc662_init_verbs,
18348 alc663_21jd_amic_init_verbs },
18349 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18350 .hp_nid = 0x03,
18351 .dac_nids = alc662_dac_nids,
18352 .dig_out_nid = ALC662_DIGOUT_NID,
18353 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18354 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018355 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018356 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018357 .init_hook = alc663_mode1_inithook,
18358 },
18359 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018360 .mixers = { alc662_1bjd_mixer },
18361 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018362 .init_verbs = { alc662_init_verbs,
18363 alc662_1bjd_amic_init_verbs },
18364 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18365 .dac_nids = alc662_dac_nids,
18366 .dig_out_nid = ALC662_DIGOUT_NID,
18367 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18368 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018369 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018370 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018371 .init_hook = alc662_mode2_inithook,
18372 },
18373 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018374 .mixers = { alc663_two_hp_m1_mixer },
18375 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018376 .init_verbs = { alc662_init_verbs,
18377 alc663_two_hp_amic_m1_init_verbs },
18378 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18379 .hp_nid = 0x03,
18380 .dac_nids = alc662_dac_nids,
18381 .dig_out_nid = ALC662_DIGOUT_NID,
18382 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18383 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018384 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018385 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018386 .init_hook = alc663_mode3_inithook,
18387 },
18388 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018389 .mixers = { alc663_asus_21jd_clfe_mixer },
18390 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018391 .init_verbs = { alc662_init_verbs,
18392 alc663_21jd_amic_init_verbs},
18393 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18394 .hp_nid = 0x03,
18395 .dac_nids = alc662_dac_nids,
18396 .dig_out_nid = ALC662_DIGOUT_NID,
18397 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18398 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018399 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018400 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018401 .init_hook = alc663_mode4_inithook,
18402 },
18403 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018404 .mixers = { alc663_asus_15jd_clfe_mixer },
18405 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018406 .init_verbs = { alc662_init_verbs,
18407 alc663_15jd_amic_init_verbs },
18408 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18409 .hp_nid = 0x03,
18410 .dac_nids = alc662_dac_nids,
18411 .dig_out_nid = ALC662_DIGOUT_NID,
18412 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18413 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018414 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018415 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018416 .init_hook = alc663_mode5_inithook,
18417 },
18418 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018419 .mixers = { alc663_two_hp_m2_mixer },
18420 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018421 .init_verbs = { alc662_init_verbs,
18422 alc663_two_hp_amic_m2_init_verbs },
18423 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18424 .hp_nid = 0x03,
18425 .dac_nids = alc662_dac_nids,
18426 .dig_out_nid = ALC662_DIGOUT_NID,
18427 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18428 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018429 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018430 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018431 .init_hook = alc663_mode6_inithook,
18432 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018433 [ALC663_ASUS_MODE7] = {
18434 .mixers = { alc663_mode7_mixer },
18435 .cap_mixer = alc662_auto_capture_mixer,
18436 .init_verbs = { alc662_init_verbs,
18437 alc663_mode7_init_verbs },
18438 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18439 .hp_nid = 0x03,
18440 .dac_nids = alc662_dac_nids,
18441 .dig_out_nid = ALC662_DIGOUT_NID,
18442 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18443 .channel_mode = alc662_3ST_2ch_modes,
18444 .unsol_event = alc663_mode7_unsol_event,
18445 .setup = alc663_mode7_setup,
18446 .init_hook = alc663_mode7_inithook,
18447 },
18448 [ALC663_ASUS_MODE8] = {
18449 .mixers = { alc663_mode8_mixer },
18450 .cap_mixer = alc662_auto_capture_mixer,
18451 .init_verbs = { alc662_init_verbs,
18452 alc663_mode8_init_verbs },
18453 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18454 .hp_nid = 0x03,
18455 .dac_nids = alc662_dac_nids,
18456 .dig_out_nid = ALC662_DIGOUT_NID,
18457 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18458 .channel_mode = alc662_3ST_2ch_modes,
18459 .unsol_event = alc663_mode8_unsol_event,
18460 .setup = alc663_mode8_setup,
18461 .init_hook = alc663_mode8_inithook,
18462 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018463 [ALC272_DELL] = {
18464 .mixers = { alc663_m51va_mixer },
18465 .cap_mixer = alc272_auto_capture_mixer,
18466 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18467 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18468 .dac_nids = alc662_dac_nids,
18469 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18470 .adc_nids = alc272_adc_nids,
18471 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18472 .capsrc_nids = alc272_capsrc_nids,
18473 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018474 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018475 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018476 .init_hook = alc663_m51va_inithook,
18477 },
18478 [ALC272_DELL_ZM1] = {
18479 .mixers = { alc663_m51va_mixer },
18480 .cap_mixer = alc662_auto_capture_mixer,
18481 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18482 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18483 .dac_nids = alc662_dac_nids,
18484 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18485 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018486 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018487 .capsrc_nids = alc662_capsrc_nids,
18488 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018489 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018490 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018491 .init_hook = alc663_m51va_inithook,
18492 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018493 [ALC272_SAMSUNG_NC10] = {
18494 .mixers = { alc272_nc10_mixer },
18495 .init_verbs = { alc662_init_verbs,
18496 alc663_21jd_amic_init_verbs },
18497 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18498 .dac_nids = alc272_dac_nids,
18499 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18500 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018501 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020018502 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018503 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018504 .init_hook = alc663_mode4_inithook,
18505 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018506};
18507
18508
18509/*
18510 * BIOS auto configuration
18511 */
18512
Takashi Iwai7085ec12009-10-02 09:03:58 +020018513/* convert from MIX nid to DAC */
18514static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
18515{
18516 if (nid == 0x0f)
18517 return 0x02;
18518 else if (nid >= 0x0c && nid <= 0x0e)
18519 return nid - 0x0c + 0x02;
18520 else
18521 return 0;
18522}
18523
18524/* get MIX nid connected to the given pin targeted to DAC */
18525static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
18526 hda_nid_t dac)
18527{
18528 hda_nid_t mix[4];
18529 int i, num;
18530
18531 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18532 for (i = 0; i < num; i++) {
18533 if (alc662_mix_to_dac(mix[i]) == dac)
18534 return mix[i];
18535 }
18536 return 0;
18537}
18538
18539/* look for an empty DAC slot */
18540static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
18541{
18542 struct alc_spec *spec = codec->spec;
18543 hda_nid_t srcs[5];
18544 int i, j, num;
18545
18546 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
18547 if (num < 0)
18548 return 0;
18549 for (i = 0; i < num; i++) {
18550 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
18551 if (!nid)
18552 continue;
18553 for (j = 0; j < spec->multiout.num_dacs; j++)
18554 if (spec->multiout.dac_nids[j] == nid)
18555 break;
18556 if (j >= spec->multiout.num_dacs)
18557 return nid;
18558 }
18559 return 0;
18560}
18561
18562/* fill in the dac_nids table from the parsed pin configuration */
18563static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
18564 const struct auto_pin_cfg *cfg)
18565{
18566 struct alc_spec *spec = codec->spec;
18567 int i;
18568 hda_nid_t dac;
18569
18570 spec->multiout.dac_nids = spec->private_dac_nids;
18571 for (i = 0; i < cfg->line_outs; i++) {
18572 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
18573 if (!dac)
18574 continue;
18575 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
18576 }
18577 return 0;
18578}
18579
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018580static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018581 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018582{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018583 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018584 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
18585}
18586
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018587static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018588 hda_nid_t nid, unsigned int chs)
18589{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018590 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018591 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
18592}
18593
18594#define alc662_add_stereo_vol(spec, pfx, nid) \
18595 alc662_add_vol_ctl(spec, pfx, nid, 3)
18596#define alc662_add_stereo_sw(spec, pfx, nid) \
18597 alc662_add_sw_ctl(spec, pfx, nid, 3)
18598
18599/* add playback controls from the parsed DAC table */
18600static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
18601 const struct auto_pin_cfg *cfg)
18602{
18603 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018604 static const char *chname[4] = {
18605 "Front", "Surround", NULL /*CLFE*/, "Side"
18606 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020018607 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018608 int i, err;
18609
18610 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018611 nid = spec->multiout.dac_nids[i];
18612 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018613 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018614 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
18615 if (!mix)
18616 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018617 if (i == 2) {
18618 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018619 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018620 if (err < 0)
18621 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018622 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018623 if (err < 0)
18624 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018625 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018626 if (err < 0)
18627 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018628 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018629 if (err < 0)
18630 return err;
18631 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018632 const char *pfx;
18633 if (cfg->line_outs == 1 &&
18634 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018635 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018636 pfx = "Speaker";
18637 else
18638 pfx = "PCM";
18639 } else
18640 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018641 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018642 if (err < 0)
18643 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020018644 if (cfg->line_outs == 1 &&
18645 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
18646 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020018647 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018648 if (err < 0)
18649 return err;
18650 }
18651 }
18652 return 0;
18653}
18654
18655/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018656/* return DAC nid if any new DAC is assigned */
18657static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018658 const char *pfx)
18659{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018660 struct alc_spec *spec = codec->spec;
18661 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018662 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018663
18664 if (!pin)
18665 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018666 nid = alc662_look_for_dac(codec, pin);
18667 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018668 /* the corresponding DAC is already occupied */
18669 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18670 return 0; /* no way */
18671 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018672 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018673 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18674 }
18675
18676 mix = alc662_dac_to_mix(codec, pin, nid);
18677 if (!mix)
18678 return 0;
18679 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
18680 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018681 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018682 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
18683 if (err < 0)
18684 return err;
18685 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018686}
18687
18688/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018689#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018690 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018691
18692static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
18693 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018694 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018695{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018696 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020018697 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018698
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018699 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018700 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020018701 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
18702 if (num <= 1)
18703 return;
18704 for (i = 0; i < num; i++) {
18705 if (alc662_mix_to_dac(srcs[i]) != dac)
18706 continue;
18707 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18708 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018709 }
18710}
18711
18712static void alc662_auto_init_multi_out(struct hda_codec *codec)
18713{
18714 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018715 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018716 int i;
18717
18718 for (i = 0; i <= HDA_SIDE; i++) {
18719 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18720 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020018721 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018722 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018723 }
18724}
18725
18726static void alc662_auto_init_hp_out(struct hda_codec *codec)
18727{
18728 struct alc_spec *spec = codec->spec;
18729 hda_nid_t pin;
18730
18731 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018732 if (pin)
18733 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
18734 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018735 pin = spec->autocfg.speaker_pins[0];
18736 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018737 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
18738 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018739}
18740
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018741#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
18742
18743static void alc662_auto_init_analog_input(struct hda_codec *codec)
18744{
18745 struct alc_spec *spec = codec->spec;
18746 int i;
18747
18748 for (i = 0; i < AUTO_PIN_LAST; i++) {
18749 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020018750 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010018751 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010018752 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010018753 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018754 snd_hda_codec_write(codec, nid, 0,
18755 AC_VERB_SET_AMP_GAIN_MUTE,
18756 AMP_OUT_MUTE);
18757 }
18758 }
18759}
18760
Takashi Iwaif511b012008-08-15 16:46:42 +020018761#define alc662_auto_init_input_src alc882_auto_init_input_src
18762
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018763static int alc662_parse_auto_config(struct hda_codec *codec)
18764{
18765 struct alc_spec *spec = codec->spec;
18766 int err;
18767 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
18768
18769 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18770 alc662_ignore);
18771 if (err < 0)
18772 return err;
18773 if (!spec->autocfg.line_outs)
18774 return 0; /* can't find valid BIOS pin config */
18775
Takashi Iwai7085ec12009-10-02 09:03:58 +020018776 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018777 if (err < 0)
18778 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018779 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018780 if (err < 0)
18781 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018782 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018783 spec->autocfg.speaker_pins[0],
18784 "Speaker");
18785 if (err < 0)
18786 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018787 if (err)
18788 spec->multiout.extra_out_nid[0] = err;
18789 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018790 "Headphone");
18791 if (err < 0)
18792 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018793 if (err)
18794 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018795 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018796 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018797 return err;
18798
18799 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18800
Takashi Iwai757899a2010-07-30 10:48:14 +020018801 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018802
Takashi Iwai603c4012008-07-30 15:01:44 +020018803 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018804 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018805
18806 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018807 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018808
Kailang Yangcec27c82010-02-04 14:18:18 +010018809 add_verb(spec, alc662_init_verbs);
18810 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018811 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010018812 add_verb(spec, alc663_init_verbs);
18813
18814 if (codec->vendor_id == 0x10ec0272)
18815 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018816
18817 err = alc_auto_add_mic_boost(codec);
18818 if (err < 0)
18819 return err;
18820
Kailang Yang6227cdc2010-02-25 08:36:52 +010018821 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18822 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18823 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18824 else
18825 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018826
Takashi Iwai8c872862007-06-19 12:11:16 +020018827 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018828}
18829
18830/* additional initialization for auto-configuration model */
18831static void alc662_auto_init(struct hda_codec *codec)
18832{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018833 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018834 alc662_auto_init_multi_out(codec);
18835 alc662_auto_init_hp_out(codec);
18836 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018837 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020018838 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018839 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018840 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018841}
18842
18843static int patch_alc662(struct hda_codec *codec)
18844{
18845 struct alc_spec *spec;
18846 int err, board_config;
18847
18848 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18849 if (!spec)
18850 return -ENOMEM;
18851
18852 codec->spec = spec;
18853
Kailang Yangda00c242010-03-19 11:23:45 +010018854 alc_auto_parse_customize_define(codec);
18855
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018856 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18857
Kailang Yangc027ddc2010-03-19 11:33:06 +010018858 if (alc_read_coef_idx(codec, 0) == 0x8020)
18859 alc_codec_rename(codec, "ALC661");
18860 else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
18861 codec->bus->pci->subsystem_vendor == 0x1025 &&
18862 spec->cdefine.platform_type == 1)
18863 alc_codec_rename(codec, "ALC272X");
Kailang Yang274693f2009-12-03 10:07:50 +010018864
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018865 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18866 alc662_models,
18867 alc662_cfg_tbl);
18868 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018869 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18870 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018871 board_config = ALC662_AUTO;
18872 }
18873
18874 if (board_config == ALC662_AUTO) {
18875 /* automatic parse from the BIOS config */
18876 err = alc662_parse_auto_config(codec);
18877 if (err < 0) {
18878 alc_free(codec);
18879 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018880 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018881 printk(KERN_INFO
18882 "hda_codec: Cannot set up configuration "
18883 "from BIOS. Using base mode...\n");
18884 board_config = ALC662_3ST_2ch_DIG;
18885 }
18886 }
18887
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018888 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020018889 err = snd_hda_attach_beep_device(codec, 0x1);
18890 if (err < 0) {
18891 alc_free(codec);
18892 return err;
18893 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018894 }
18895
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018896 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018897 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018898
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018899 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18900 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18901
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018902 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18903 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18904
Takashi Iwaidd704692009-08-11 08:45:11 +020018905 if (!spec->adc_nids) {
18906 spec->adc_nids = alc662_adc_nids;
18907 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18908 }
18909 if (!spec->capsrc_nids)
18910 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018911
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018912 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018913 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018914
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018915 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010018916 switch (codec->vendor_id) {
18917 case 0x10ec0662:
18918 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18919 break;
18920 case 0x10ec0272:
18921 case 0x10ec0663:
18922 case 0x10ec0665:
18923 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18924 break;
18925 case 0x10ec0273:
18926 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18927 break;
18928 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018929 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018930 spec->vmaster_nid = 0x02;
18931
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018932 codec->patch_ops = alc_patch_ops;
18933 if (board_config == ALC662_AUTO)
18934 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018935#ifdef CONFIG_SND_HDA_POWER_SAVE
18936 if (!spec->loopback.amplist)
18937 spec->loopback.amplist = alc662_loopbacks;
18938#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018939
18940 return 0;
18941}
18942
Kailang Yang274693f2009-12-03 10:07:50 +010018943static int patch_alc888(struct hda_codec *codec)
18944{
18945 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18946 kfree(codec->chip_name);
18947 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018948 if (!codec->chip_name) {
18949 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018950 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018951 }
18952 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018953 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018954 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018955}
18956
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018957/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018958 * ALC680 support
18959 */
18960#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
18961#define alc680_modes alc260_modes
18962
18963static hda_nid_t alc680_dac_nids[3] = {
18964 /* Lout1, Lout2, hp */
18965 0x02, 0x03, 0x04
18966};
18967
18968static hda_nid_t alc680_adc_nids[3] = {
18969 /* ADC0-2 */
18970 /* DMIC, MIC, Line-in*/
18971 0x07, 0x08, 0x09
18972};
18973
18974static struct snd_kcontrol_new alc680_base_mixer[] = {
18975 /* output mixer control */
18976 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
18977 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18978 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
18979 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
18980 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
18981 { }
18982};
18983
18984static struct snd_kcontrol_new alc680_capture_mixer[] = {
18985 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
18986 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
18987 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
18988 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
18989 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
18990 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
18991 { } /* end */
18992};
18993
18994/*
18995 * generic initialization of ADC, input mixers and output mixers
18996 */
18997static struct hda_verb alc680_init_verbs[] = {
18998 /* Unmute DAC0-1 and set vol = 0 */
18999 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
19000 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
19001 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
19002
19003 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19004 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
19005 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
19006 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
19007 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
19008
19009 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19010 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19011 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19012 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19013 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19014 { }
19015};
19016
19017/* create input playback/capture controls for the given pin */
19018static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19019 const char *ctlname, int idx)
19020{
19021 hda_nid_t dac;
19022 int err;
19023
19024 switch (nid) {
19025 case 0x14:
19026 dac = 0x02;
19027 break;
19028 case 0x15:
19029 dac = 0x03;
19030 break;
19031 case 0x16:
19032 dac = 0x04;
19033 break;
19034 default:
19035 return 0;
19036 }
19037 if (spec->multiout.dac_nids[0] != dac &&
19038 spec->multiout.dac_nids[1] != dac) {
19039 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19040 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19041 HDA_OUTPUT));
19042 if (err < 0)
19043 return err;
19044
19045 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19046 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19047
19048 if (err < 0)
19049 return err;
19050 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19051 }
19052
19053 return 0;
19054}
19055
19056/* add playback controls from the parsed DAC table */
19057static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19058 const struct auto_pin_cfg *cfg)
19059{
19060 hda_nid_t nid;
19061 int err;
19062
19063 spec->multiout.dac_nids = spec->private_dac_nids;
19064
19065 nid = cfg->line_out_pins[0];
19066 if (nid) {
19067 const char *name;
19068 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19069 name = "Speaker";
19070 else
19071 name = "Front";
19072 err = alc680_new_analog_output(spec, nid, name, 0);
19073 if (err < 0)
19074 return err;
19075 }
19076
19077 nid = cfg->speaker_pins[0];
19078 if (nid) {
19079 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19080 if (err < 0)
19081 return err;
19082 }
19083 nid = cfg->hp_pins[0];
19084 if (nid) {
19085 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19086 if (err < 0)
19087 return err;
19088 }
19089
19090 return 0;
19091}
19092
19093static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19094 hda_nid_t nid, int pin_type)
19095{
19096 alc_set_pin_output(codec, nid, pin_type);
19097}
19098
19099static void alc680_auto_init_multi_out(struct hda_codec *codec)
19100{
19101 struct alc_spec *spec = codec->spec;
19102 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19103 if (nid) {
19104 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19105 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19106 }
19107}
19108
19109static void alc680_auto_init_hp_out(struct hda_codec *codec)
19110{
19111 struct alc_spec *spec = codec->spec;
19112 hda_nid_t pin;
19113
19114 pin = spec->autocfg.hp_pins[0];
19115 if (pin)
19116 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19117 pin = spec->autocfg.speaker_pins[0];
19118 if (pin)
19119 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19120}
19121
19122/* pcm configuration: identical with ALC880 */
19123#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19124#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19125#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19126#define alc680_pcm_digital_playback alc880_pcm_digital_playback
19127
19128static struct hda_input_mux alc680_capture_source = {
19129 .num_items = 1,
19130 .items = {
19131 { "Mic", 0x0 },
19132 },
19133};
19134
19135/*
19136 * BIOS auto configuration
19137 */
19138static int alc680_parse_auto_config(struct hda_codec *codec)
19139{
19140 struct alc_spec *spec = codec->spec;
19141 int err;
19142 static hda_nid_t alc680_ignore[] = { 0 };
19143
19144 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19145 alc680_ignore);
19146 if (err < 0)
19147 return err;
19148 if (!spec->autocfg.line_outs) {
19149 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19150 spec->multiout.max_channels = 2;
19151 spec->no_analog = 1;
19152 goto dig_only;
19153 }
19154 return 0; /* can't find valid BIOS pin config */
19155 }
19156 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19157 if (err < 0)
19158 return err;
19159
19160 spec->multiout.max_channels = 2;
19161
19162 dig_only:
19163 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019164 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019165 if (spec->kctls.list)
19166 add_mixer(spec, spec->kctls.list);
19167
19168 add_verb(spec, alc680_init_verbs);
19169 spec->num_mux_defs = 1;
19170 spec->input_mux = &alc680_capture_source;
19171
19172 err = alc_auto_add_mic_boost(codec);
19173 if (err < 0)
19174 return err;
19175
19176 return 1;
19177}
19178
19179#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19180
19181/* init callback for auto-configuration model -- overriding the default init */
19182static void alc680_auto_init(struct hda_codec *codec)
19183{
19184 struct alc_spec *spec = codec->spec;
19185 alc680_auto_init_multi_out(codec);
19186 alc680_auto_init_hp_out(codec);
19187 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019188 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019189 if (spec->unsol_event)
19190 alc_inithook(codec);
19191}
19192
19193/*
19194 * configuration and preset
19195 */
19196static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019197 [ALC680_BASE] = "base",
19198 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019199};
19200
19201static struct snd_pci_quirk alc680_cfg_tbl[] = {
19202 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19203 {}
19204};
19205
19206static struct alc_config_preset alc680_presets[] = {
19207 [ALC680_BASE] = {
19208 .mixers = { alc680_base_mixer },
19209 .cap_mixer = alc680_capture_mixer,
19210 .init_verbs = { alc680_init_verbs },
19211 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19212 .dac_nids = alc680_dac_nids,
19213 .num_adc_nids = ARRAY_SIZE(alc680_adc_nids),
19214 .adc_nids = alc680_adc_nids,
19215 .hp_nid = 0x04,
19216 .dig_out_nid = ALC680_DIGOUT_NID,
19217 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19218 .channel_mode = alc680_modes,
19219 .input_mux = &alc680_capture_source,
19220 },
19221};
19222
19223static int patch_alc680(struct hda_codec *codec)
19224{
19225 struct alc_spec *spec;
19226 int board_config;
19227 int err;
19228
19229 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19230 if (spec == NULL)
19231 return -ENOMEM;
19232
19233 codec->spec = spec;
19234
19235 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19236 alc680_models,
19237 alc680_cfg_tbl);
19238
19239 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19240 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19241 codec->chip_name);
19242 board_config = ALC680_AUTO;
19243 }
19244
19245 if (board_config == ALC680_AUTO) {
19246 /* automatic parse from the BIOS config */
19247 err = alc680_parse_auto_config(codec);
19248 if (err < 0) {
19249 alc_free(codec);
19250 return err;
19251 } else if (!err) {
19252 printk(KERN_INFO
19253 "hda_codec: Cannot set up configuration "
19254 "from BIOS. Using base mode...\n");
19255 board_config = ALC680_BASE;
19256 }
19257 }
19258
19259 if (board_config != ALC680_AUTO)
19260 setup_preset(codec, &alc680_presets[board_config]);
19261
19262 spec->stream_analog_playback = &alc680_pcm_analog_playback;
19263 spec->stream_analog_capture = &alc680_pcm_analog_capture;
19264 spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture;
19265 spec->stream_digital_playback = &alc680_pcm_digital_playback;
19266
19267 if (!spec->adc_nids) {
19268 spec->adc_nids = alc680_adc_nids;
19269 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19270 }
19271
19272 if (!spec->cap_mixer)
19273 set_capture_mixer(codec);
19274
19275 spec->vmaster_nid = 0x02;
19276
19277 codec->patch_ops = alc_patch_ops;
19278 if (board_config == ALC680_AUTO)
19279 spec->init_hook = alc680_auto_init;
19280
19281 return 0;
19282}
19283
19284/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019285 * patch entries
19286 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019287static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019288 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019289 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019290 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019291 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019292 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019293 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019294 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019295 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019296 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019297 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019298 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19299 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19300 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019301 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019302 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019303 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19304 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019305 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019306 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019307 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019308 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019309 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019310 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019311 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019312 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019313 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019314 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019315 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019316 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019317 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020019318 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019319 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019320 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019321 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019322 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019323 {} /* terminator */
19324};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019325
19326MODULE_ALIAS("snd-hda-codec-id:10ec*");
19327
19328MODULE_LICENSE("GPL");
19329MODULE_DESCRIPTION("Realtek HD-audio codec");
19330
19331static struct hda_codec_preset_list realtek_list = {
19332 .preset = snd_hda_preset_realtek,
19333 .owner = THIS_MODULE,
19334};
19335
19336static int __init patch_realtek_init(void)
19337{
19338 return snd_hda_add_codec_preset(&realtek_list);
19339}
19340
19341static void __exit patch_realtek_exit(void)
19342{
19343 snd_hda_delete_codec_preset(&realtek_list);
19344}
19345
19346module_init(patch_realtek_init)
19347module_exit(patch_realtek_exit)