blob: 7d492713c1c16955bf230da754a419a4ba29ba90 [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>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200234 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100235 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200236 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200237 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200238 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200239 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200240 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200241 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100242 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100243 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430244 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100245 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100246 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800247 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200248 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200249 ALC889A_INTEL,
250 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200251 ALC888_ASUS_M90V,
252 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200253 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100254 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200255 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-06-30 15:28:30 +0200256 ALC882_AUTO,
257 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200258};
259
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200260/* ALC680 models */
261enum {
262 ALC680_BASE,
263 ALC680_AUTO,
264 ALC680_MODEL_LAST,
265};
266
Kailang Yangdf694da2005-12-05 19:42:22 +0100267/* for GPIO Poll */
268#define GPIO_MASK 0x03
269
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200270/* extra amp-initialization sequence types */
271enum {
272 ALC_INIT_NONE,
273 ALC_INIT_DEFAULT,
274 ALC_INIT_GPIO1,
275 ALC_INIT_GPIO2,
276 ALC_INIT_GPIO3,
277};
278
Takashi Iwai6c819492009-08-10 18:47:44 +0200279struct alc_mic_route {
280 hda_nid_t pin;
281 unsigned char mux_idx;
282 unsigned char amix_idx;
283};
284
285#define MUX_IDX_UNDEF ((unsigned char)-1)
286
Kailang Yangda00c242010-03-19 11:23:45 +0100287struct alc_customize_define {
288 unsigned int sku_cfg;
289 unsigned char port_connectivity;
290 unsigned char check_sum;
291 unsigned char customization;
292 unsigned char external_amp;
293 unsigned int enable_pcbeep:1;
294 unsigned int platform_type:1;
295 unsigned int swap:1;
296 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +0200297 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +0100298};
299
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100300struct alc_fixup;
301
Takashi Iwaice764ab2011-04-27 16:35:23 +0200302struct alc_multi_io {
303 hda_nid_t pin; /* multi-io widget pin NID */
304 hda_nid_t dac; /* DAC to be connected */
305 unsigned int ctl_in; /* cached input-pin control value */
306};
307
Takashi Iwaid922b512011-04-28 12:18:53 +0200308enum {
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200309 ALC_AUTOMUTE_PIN, /* change the pin control */
310 ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */
311 ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */
Takashi Iwaid922b512011-04-28 12:18:53 +0200312};
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314struct alc_spec {
315 /* codec parameterization */
Takashi Iwaia9111322011-05-02 11:30:18 +0200316 const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 unsigned int num_mixers;
Takashi Iwaia9111322011-05-02 11:30:18 +0200318 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100319 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200321 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200322 * don't forget NULL
323 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200324 */
325 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200327 char stream_name_analog[32]; /* analog PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200328 const struct hda_pcm_stream *stream_analog_playback;
329 const struct hda_pcm_stream *stream_analog_capture;
330 const struct hda_pcm_stream *stream_analog_alt_playback;
331 const struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200333 char stream_name_digital[32]; /* digital PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200334 const struct hda_pcm_stream *stream_digital_playback;
335 const struct hda_pcm_stream *stream_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200338 struct hda_multi_out multiout; /* playback set-up
339 * max_channels, dacs must be set
340 * dig_out_nid and hp_nid are optional
341 */
Takashi Iwai63300792008-01-24 15:31:36 +0100342 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100343 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100344 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 /* capture */
347 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200348 const hda_nid_t *adc_nids;
349 const hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200350 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Takashi Iwai840b64c2010-07-13 22:49:01 +0200352 /* capture setup for dynamic dual-adc switch */
353 unsigned int cur_adc_idx;
354 hda_nid_t cur_adc;
355 unsigned int cur_adc_stream_tag;
356 unsigned int cur_adc_format;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200359 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 const struct hda_input_mux *input_mux;
361 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200362 struct alc_mic_route ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +0200363 struct alc_mic_route dock_mic;
Takashi Iwai6c819492009-08-10 18:47:44 +0200364 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100367 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200369 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200370 int const_channel_count;
371 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100374 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200375
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200376 /* dynamic controls, init_verbs and input_mux */
377 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100378 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200379 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200380 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200381 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200382 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
383 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100384
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100385 /* hooks */
386 void (*init_hook)(struct hda_codec *codec);
387 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100388#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500389 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100390#endif
Takashi Iwai1c716152011-04-07 10:37:16 +0200391 void (*shutup)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100392
Takashi Iwai834be882006-03-01 14:16:17 +0100393 /* for pin sensing */
Takashi Iwai834be882006-03-01 14:16:17 +0100394 unsigned int jack_present: 1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200395 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200396 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200397 unsigned int auto_mic:1;
Takashi Iwaid922b512011-04-28 12:18:53 +0200398 unsigned int automute:1; /* HP automute enabled */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200399 unsigned int detect_line:1; /* Line-out detection enabled */
400 unsigned int automute_lines:1; /* automute line-out as well */
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200401 unsigned int automute_hp_lo:1; /* both HP and LO available */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200402
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100403 /* other flags */
404 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200405 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai584c0c42011-03-10 12:51:11 +0100406 unsigned int single_input_src:1;
Takashi Iwaid922b512011-04-28 12:18:53 +0200407
408 /* auto-mute control */
409 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200410 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200411
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200412 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200413 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100414
Takashi Iwai2134ea42008-01-10 16:53:55 +0100415 /* for virtual master */
416 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200417#ifdef CONFIG_SND_HDA_POWER_SAVE
418 struct hda_loopback_check loopback;
419#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200420
421 /* for PLL fix */
422 hda_nid_t pll_nid;
423 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100424
425 /* fix-up list */
426 int fixup_id;
427 const struct alc_fixup *fixup_list;
428 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200429
430 /* multi-io */
431 int multi_ios;
432 struct alc_multi_io multi_io[4];
Kailang Yangdf694da2005-12-05 19:42:22 +0100433};
434
435/*
436 * configuration template - to be copied to the spec instance
437 */
438struct alc_config_preset {
Takashi Iwaia9111322011-05-02 11:30:18 +0200439 const struct snd_kcontrol_new *mixers[5]; /* should be identical size
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200440 * with spec
441 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200442 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100443 const struct hda_verb *init_verbs[5];
444 unsigned int num_dacs;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200445 const hda_nid_t *dac_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100446 hda_nid_t dig_out_nid; /* optional */
447 hda_nid_t hp_nid; /* optional */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200448 const hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100449 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200450 const hda_nid_t *adc_nids;
451 const hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100452 hda_nid_t dig_in_nid;
453 unsigned int num_channel_mode;
454 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200455 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200456 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200457 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100458 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100459 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200460 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100461 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200462#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +0200463 const struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500464 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200465#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466};
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469/*
470 * input MUX handling
471 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200472static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200477 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
478 if (mux_idx >= spec->num_mux_defs)
479 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100480 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
481 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200482 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200485static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
486 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
489 struct alc_spec *spec = codec->spec;
490 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
491
492 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
493 return 0;
494}
495
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200496static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
497 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
499 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
500 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100501 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100503 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100504 hda_nid_t nid = spec->capsrc_nids ?
505 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200506 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Takashi Iwaicd896c32008-11-18 12:36:33 +0100508 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
509 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100510 if (!imux->num_items && mux_idx > 0)
511 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100512
Takashi Iwaia22d5432009-07-27 12:54:26 +0200513 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200514 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100515 /* Matrix-mixer style (e.g. ALC882) */
516 unsigned int *cur_val = &spec->cur_mux[adc_idx];
517 unsigned int i, idx;
518
519 idx = ucontrol->value.enumerated.item[0];
520 if (idx >= imux->num_items)
521 idx = imux->num_items - 1;
522 if (*cur_val == idx)
523 return 0;
524 for (i = 0; i < imux->num_items; i++) {
525 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
526 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
527 imux->items[i].index,
528 HDA_AMP_MUTE, v);
529 }
530 *cur_val = idx;
531 return 1;
532 } else {
533 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100534 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100535 &spec->cur_mux[adc_idx]);
536 }
537}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539/*
540 * channel mode setting
541 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200542static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
543 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
546 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100547 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
548 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200551static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
552 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
555 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100556 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200557 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200558 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200561static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
565 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200566 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
567 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200568 &spec->ext_channel_count);
569 if (err >= 0 && !spec->const_channel_count) {
570 spec->multiout.max_channels = spec->ext_channel_count;
571 if (spec->need_dac_fix)
572 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
573 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200574 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100578 * Control the mode of pin widget settings via the mixer. "pc" is used
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300579 * instead of "%" to avoid consequences of accidentally treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100580 * being part of a format specifier. Maximum allowed length of a value is
581 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100582 *
583 * Note: some retasking pin complexes seem to ignore requests for input
584 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
585 * are requested. Therefore order this list so that this behaviour will not
586 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200587 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
588 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200589 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200590static const char * const alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100591 "Mic 50pc bias", "Mic 80pc bias",
592 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100593};
Takashi Iwaia9111322011-05-02 11:30:18 +0200594static const unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100595 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100596};
597/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200598 * in the pin being assumed to be exclusively an input or an output pin. In
599 * addition, "input" pins may or may not process the mic bias option
600 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
601 * accept requests for bias as of chip versions up to March 2006) and/or
602 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100603 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200604#define ALC_PIN_DIR_IN 0x00
605#define ALC_PIN_DIR_OUT 0x01
606#define ALC_PIN_DIR_INOUT 0x02
607#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
608#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100609
Kailang Yangea1fb292008-08-26 12:58:38 +0200610/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100611 * For each direction the minimum and maximum values are given.
612 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200613static const signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100614 { 0, 2 }, /* ALC_PIN_DIR_IN */
615 { 3, 4 }, /* ALC_PIN_DIR_OUT */
616 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200617 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
618 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100619};
620#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
621#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
622#define alc_pin_mode_n_items(_dir) \
623 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
624
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200625static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
626 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200627{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100628 unsigned int item_num = uinfo->value.enumerated.item;
629 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
630
631 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200632 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100633 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
634
635 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
636 item_num = alc_pin_mode_min(dir);
637 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200638 return 0;
639}
640
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200641static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
642 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200643{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100644 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200645 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
646 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100647 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200648 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200649 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
650 AC_VERB_GET_PIN_WIDGET_CONTROL,
651 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200652
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100653 /* Find enumerated value for current pinctl setting */
654 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200655 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100656 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200657 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100658 return 0;
659}
660
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200661static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
662 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100663{
664 signed int change;
665 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
666 hda_nid_t nid = kcontrol->private_value & 0xffff;
667 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
668 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200669 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
670 AC_VERB_GET_PIN_WIDGET_CONTROL,
671 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100672
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200673 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100674 val = alc_pin_mode_min(dir);
675
676 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100677 if (change) {
678 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200679 snd_hda_codec_write_cache(codec, nid, 0,
680 AC_VERB_SET_PIN_WIDGET_CONTROL,
681 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100682
Kailang Yangea1fb292008-08-26 12:58:38 +0200683 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100684 * for the requested pin mode. Enum values of 2 or less are
685 * input modes.
686 *
687 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200688 * reduces noise slightly (particularly on input) so we'll
689 * do it. However, having both input and output buffers
690 * enabled simultaneously doesn't seem to be problematic if
691 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100692 */
693 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200694 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
695 HDA_AMP_MUTE, HDA_AMP_MUTE);
696 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
697 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100698 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200699 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
700 HDA_AMP_MUTE, HDA_AMP_MUTE);
701 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
702 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100703 }
704 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200705 return change;
706}
707
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100708#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200709 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100710 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100711 .info = alc_pin_mode_info, \
712 .get = alc_pin_mode_get, \
713 .put = alc_pin_mode_put, \
714 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100715
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100716/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
717 * together using a mask with more than one bit set. This control is
718 * currently used only by the ALC260 test model. At this stage they are not
719 * needed for any "production" models.
720 */
721#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200722#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200723
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200724static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
725 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100726{
727 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
728 hda_nid_t nid = kcontrol->private_value & 0xffff;
729 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
730 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200731 unsigned int val = snd_hda_codec_read(codec, nid, 0,
732 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100733
734 *valp = (val & mask) != 0;
735 return 0;
736}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200737static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
738 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100739{
740 signed int change;
741 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
742 hda_nid_t nid = kcontrol->private_value & 0xffff;
743 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
744 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200745 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
746 AC_VERB_GET_GPIO_DATA,
747 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100748
749 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200750 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
751 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100752 gpio_data &= ~mask;
753 else
754 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200755 snd_hda_codec_write_cache(codec, nid, 0,
756 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100757
758 return change;
759}
760#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
761 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100762 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100763 .info = alc_gpio_data_info, \
764 .get = alc_gpio_data_get, \
765 .put = alc_gpio_data_put, \
766 .private_value = nid | (mask<<16) }
767#endif /* CONFIG_SND_DEBUG */
768
Jonathan Woithe92621f12006-02-28 11:47:47 +0100769/* A switch control to allow the enabling of the digital IO pins on the
770 * ALC260. This is incredibly simplistic; the intention of this control is
771 * to provide something in the test model allowing digital outputs to be
772 * identified if present. If models are found which can utilise these
773 * outputs a more complete mixer control can be devised for those models if
774 * necessary.
775 */
776#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200777#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200778
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200779static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
780 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100781{
782 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
783 hda_nid_t nid = kcontrol->private_value & 0xffff;
784 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
785 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200786 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100787 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100788
789 *valp = (val & mask) != 0;
790 return 0;
791}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200792static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
793 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100794{
795 signed int change;
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 val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200800 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100801 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200802 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100803
804 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200805 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100806 if (val==0)
807 ctrl_data &= ~mask;
808 else
809 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200810 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
811 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100812
813 return change;
814}
815#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
816 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100817 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100818 .info = alc_spdif_ctrl_info, \
819 .get = alc_spdif_ctrl_get, \
820 .put = alc_spdif_ctrl_put, \
821 .private_value = nid | (mask<<16) }
822#endif /* CONFIG_SND_DEBUG */
823
Jonathan Woithef8225f62008-01-08 12:16:54 +0100824/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
825 * Again, this is only used in the ALC26x test models to help identify when
826 * the EAPD line must be asserted for features to work.
827 */
828#ifdef CONFIG_SND_DEBUG
829#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
830
831static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
832 struct snd_ctl_elem_value *ucontrol)
833{
834 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
835 hda_nid_t nid = kcontrol->private_value & 0xffff;
836 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
837 long *valp = ucontrol->value.integer.value;
838 unsigned int val = snd_hda_codec_read(codec, nid, 0,
839 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
840
841 *valp = (val & mask) != 0;
842 return 0;
843}
844
845static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
846 struct snd_ctl_elem_value *ucontrol)
847{
848 int change;
849 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
850 hda_nid_t nid = kcontrol->private_value & 0xffff;
851 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
852 long val = *ucontrol->value.integer.value;
853 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
854 AC_VERB_GET_EAPD_BTLENABLE,
855 0x00);
856
857 /* Set/unset the masked control bit(s) as needed */
858 change = (!val ? 0 : mask) != (ctrl_data & mask);
859 if (!val)
860 ctrl_data &= ~mask;
861 else
862 ctrl_data |= mask;
863 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
864 ctrl_data);
865
866 return change;
867}
868
869#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
870 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100871 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100872 .info = alc_eapd_ctrl_info, \
873 .get = alc_eapd_ctrl_get, \
874 .put = alc_eapd_ctrl_put, \
875 .private_value = nid | (mask<<16) }
876#endif /* CONFIG_SND_DEBUG */
877
Kailang Yangdf694da2005-12-05 19:42:22 +0100878/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100879 * set up the input pin config (depending on the given auto-pin type)
880 */
881static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
882 int auto_pin_type)
883{
884 unsigned int val = PIN_IN;
885
Takashi Iwai86e29592010-09-09 14:50:17 +0200886 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100887 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200888 unsigned int oldval;
889 oldval = snd_hda_codec_read(codec, nid, 0,
890 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100891 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100892 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200893 /* if the default pin setup is vref50, we give it priority */
894 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100895 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200896 else if (pincap & AC_PINCAP_VREF_50)
897 val = PIN_VREF50;
898 else if (pincap & AC_PINCAP_VREF_100)
899 val = PIN_VREF100;
900 else if (pincap & AC_PINCAP_VREF_GRD)
901 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100902 }
903 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
904}
905
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200906static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
907{
908 struct alc_spec *spec = codec->spec;
909 struct auto_pin_cfg *cfg = &spec->autocfg;
910
911 if (!cfg->line_outs) {
912 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
913 cfg->line_out_pins[cfg->line_outs])
914 cfg->line_outs++;
915 }
916 if (!cfg->speaker_outs) {
917 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
918 cfg->speaker_pins[cfg->speaker_outs])
919 cfg->speaker_outs++;
920 }
921 if (!cfg->hp_outs) {
922 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
923 cfg->hp_pins[cfg->hp_outs])
924 cfg->hp_outs++;
925 }
926}
927
Takashi Iwai23f0c042009-02-26 13:03:58 +0100928/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100929 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200930static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100931{
932 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
933 return;
934 spec->mixers[spec->num_mixers++] = mix;
935}
936
937static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
938{
939 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
940 return;
941 spec->init_verbs[spec->num_init_verbs++] = verb;
942}
943
944/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100945 * set up from the preset table
946 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200947static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200948 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100949{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200950 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100951 int i;
952
953 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100954 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100955 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200956 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
957 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100958 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200959
Kailang Yangdf694da2005-12-05 19:42:22 +0100960 spec->channel_mode = preset->channel_mode;
961 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200962 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200963 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100964
Hector Martin3b315d72009-06-02 10:54:19 +0200965 if (preset->const_channel_count)
966 spec->multiout.max_channels = preset->const_channel_count;
967 else
968 spec->multiout.max_channels = spec->channel_mode[0].channels;
969 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100970
971 spec->multiout.num_dacs = preset->num_dacs;
972 spec->multiout.dac_nids = preset->dac_nids;
973 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800974 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100975 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200976
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200977 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200978 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200979 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100980 spec->input_mux = preset->input_mux;
981
982 spec->num_adc_nids = preset->num_adc_nids;
983 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100984 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100985 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100986
987 spec->unsol_event = preset->unsol_event;
988 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200989#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100990 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200991 spec->loopback.amplist = preset->loopbacks;
992#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200993
994 if (preset->setup)
995 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200996
997 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100998}
999
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001000/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +02001001static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001002 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1003 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1004 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1005 { }
1006};
1007
Takashi Iwaia9111322011-05-02 11:30:18 +02001008static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001009 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1010 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1011 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1012 { }
1013};
1014
Takashi Iwaia9111322011-05-02 11:30:18 +02001015static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02001016 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
1017 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
1018 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
1019 { }
1020};
1021
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001022/*
1023 * Fix hardware PLL issue
1024 * On some codecs, the analog PLL gating control must be off while
1025 * the default value is 1.
1026 */
1027static void alc_fix_pll(struct hda_codec *codec)
1028{
1029 struct alc_spec *spec = codec->spec;
1030 unsigned int val;
1031
1032 if (!spec->pll_nid)
1033 return;
1034 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1035 spec->pll_coef_idx);
1036 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1037 AC_VERB_GET_PROC_COEF, 0);
1038 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1039 spec->pll_coef_idx);
1040 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1041 val & ~(1 << spec->pll_coef_bit));
1042}
1043
1044static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1045 unsigned int coef_idx, unsigned int coef_bit)
1046{
1047 struct alc_spec *spec = codec->spec;
1048 spec->pll_nid = nid;
1049 spec->pll_coef_idx = coef_idx;
1050 spec->pll_coef_bit = coef_bit;
1051 alc_fix_pll(codec);
1052}
1053
Kailang Yang9ad0e492010-09-14 23:22:00 +02001054static int alc_init_jacks(struct hda_codec *codec)
1055{
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001056#ifdef CONFIG_SND_HDA_INPUT_JACK
Kailang Yang9ad0e492010-09-14 23:22:00 +02001057 struct alc_spec *spec = codec->spec;
1058 int err;
1059 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1060 unsigned int mic_nid = spec->ext_mic.pin;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001061 unsigned int dock_nid = spec->dock_mic.pin;
Kailang Yang9ad0e492010-09-14 23:22:00 +02001062
Takashi Iwai265a0242010-09-21 11:26:21 +02001063 if (hp_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001064 err = snd_hda_input_jack_add(codec, hp_nid,
1065 SND_JACK_HEADPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001066 if (err < 0)
1067 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001068 snd_hda_input_jack_report(codec, hp_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001069 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001070
Takashi Iwai265a0242010-09-21 11:26:21 +02001071 if (mic_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001072 err = snd_hda_input_jack_add(codec, mic_nid,
1073 SND_JACK_MICROPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001074 if (err < 0)
1075 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001076 snd_hda_input_jack_report(codec, mic_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001077 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001078 if (dock_nid) {
1079 err = snd_hda_input_jack_add(codec, dock_nid,
1080 SND_JACK_MICROPHONE, NULL);
1081 if (err < 0)
1082 return err;
1083 snd_hda_input_jack_report(codec, dock_nid);
1084 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001085#endif /* CONFIG_SND_HDA_INPUT_JACK */
Kailang Yang9ad0e492010-09-14 23:22:00 +02001086 return 0;
1087}
Kailang Yang9ad0e492010-09-14 23:22:00 +02001088
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001089static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +02001090{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001091 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +02001092
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001093 for (i = 0; i < num_pins; i++) {
1094 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001095 if (!nid)
1096 break;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001097 snd_hda_input_jack_report(codec, nid);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001098 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001099 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001100 return present;
1101}
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001102
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001103static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +02001104 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001105{
1106 struct alc_spec *spec = codec->spec;
1107 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02001108 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001109 int i;
1110
1111 for (i = 0; i < num_pins; i++) {
1112 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001113 if (!nid)
1114 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001115 switch (spec->automute_mode) {
1116 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001117 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001118 AC_VERB_SET_PIN_WIDGET_CONTROL,
1119 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001120 break;
1121 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001122 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001123 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001124 break;
1125 case ALC_AUTOMUTE_MIXER:
1126 nid = spec->automute_mixer_nid[i];
1127 if (!nid)
1128 break;
1129 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001130 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001131 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001132 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001133 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001134 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001135 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001136}
1137
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001138/* Toggle internal speakers muting */
1139static void update_speakers(struct hda_codec *codec)
1140{
1141 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001142 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001143
Takashi Iwaic0a20262011-06-10 15:28:15 +02001144 /* Control HP pins/amps depending on master_mute state;
1145 * in general, HP pins/amps control should be enabled in all cases,
1146 * but currently set only for master_mute, just to be safe
1147 */
1148 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1149 spec->autocfg.hp_pins, spec->master_mute, true);
1150
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001151 if (!spec->automute)
1152 on = 0;
1153 else
1154 on = spec->jack_present | spec->line_jack_present;
1155 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001156 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001157 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001158
1159 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001160 /* if LO is a copy of either HP or Speaker, don't need to handle it */
1161 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
1162 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001163 return;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001164 if (!spec->automute_lines || !spec->automute)
1165 on = 0;
1166 else
1167 on = spec->jack_present;
1168 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001169 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001170 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001171}
1172
1173static void alc_hp_automute(struct hda_codec *codec)
1174{
1175 struct alc_spec *spec = codec->spec;
1176
1177 if (!spec->automute)
1178 return;
1179 spec->jack_present =
1180 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1181 spec->autocfg.hp_pins);
1182 update_speakers(codec);
1183}
1184
1185static void alc_line_automute(struct hda_codec *codec)
1186{
1187 struct alc_spec *spec = codec->spec;
1188
1189 if (!spec->automute || !spec->detect_line)
1190 return;
1191 spec->line_jack_present =
1192 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
1193 spec->autocfg.line_out_pins);
1194 update_speakers(codec);
1195}
1196
Takashi Iwai6c819492009-08-10 18:47:44 +02001197static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1198 hda_nid_t nid)
1199{
1200 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1201 int i, nums;
1202
1203 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1204 for (i = 0; i < nums; i++)
1205 if (conn[i] == nid)
1206 return i;
1207 return -1;
1208}
1209
Takashi Iwai840b64c2010-07-13 22:49:01 +02001210/* switch the current ADC according to the jack state */
1211static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1212{
1213 struct alc_spec *spec = codec->spec;
1214 unsigned int present;
1215 hda_nid_t new_adc;
1216
1217 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1218 if (present)
1219 spec->cur_adc_idx = 1;
1220 else
1221 spec->cur_adc_idx = 0;
1222 new_adc = spec->adc_nids[spec->cur_adc_idx];
1223 if (spec->cur_adc && spec->cur_adc != new_adc) {
1224 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001225 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001226 spec->cur_adc = new_adc;
1227 snd_hda_codec_setup_stream(codec, new_adc,
1228 spec->cur_adc_stream_tag, 0,
1229 spec->cur_adc_format);
1230 }
1231}
1232
Kailang Yang7fb0d782008-10-15 11:12:35 +02001233static void alc_mic_automute(struct hda_codec *codec)
1234{
1235 struct alc_spec *spec = codec->spec;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001236 struct alc_mic_route *dead1, *dead2, *alive;
Takashi Iwai6c819492009-08-10 18:47:44 +02001237 unsigned int present, type;
1238 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001239
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001240 if (!spec->auto_mic)
1241 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001242 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1243 return;
1244 if (snd_BUG_ON(!spec->adc_nids))
1245 return;
1246
Takashi Iwai840b64c2010-07-13 22:49:01 +02001247 if (spec->dual_adc_switch) {
1248 alc_dual_mic_adc_auto_switch(codec);
1249 return;
1250 }
1251
Takashi Iwai6c819492009-08-10 18:47:44 +02001252 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1253
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001254 alive = &spec->int_mic;
1255 dead1 = &spec->ext_mic;
1256 dead2 = &spec->dock_mic;
1257
Wu Fengguang864f92b2009-11-18 12:38:02 +08001258 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001259 if (present) {
1260 alive = &spec->ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001261 dead1 = &spec->int_mic;
1262 dead2 = &spec->dock_mic;
1263 }
1264 if (!present && spec->dock_mic.pin > 0) {
1265 present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
1266 if (present) {
1267 alive = &spec->dock_mic;
1268 dead1 = &spec->int_mic;
1269 dead2 = &spec->ext_mic;
1270 }
1271 snd_hda_input_jack_report(codec, spec->dock_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001272 }
1273
Takashi Iwai6c819492009-08-10 18:47:44 +02001274 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1275 if (type == AC_WID_AUD_MIX) {
1276 /* Matrix-mixer style (e.g. ALC882) */
1277 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1278 alive->mux_idx,
1279 HDA_AMP_MUTE, 0);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001280 if (dead1->pin > 0)
1281 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1282 dead1->mux_idx,
1283 HDA_AMP_MUTE, HDA_AMP_MUTE);
1284 if (dead2->pin > 0)
1285 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1286 dead2->mux_idx,
1287 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai6c819492009-08-10 18:47:44 +02001288 } else {
1289 /* MUX style (e.g. ALC880) */
1290 snd_hda_codec_write_cache(codec, cap_nid, 0,
1291 AC_VERB_SET_CONNECT_SEL,
1292 alive->mux_idx);
1293 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001294 snd_hda_input_jack_report(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001295
1296 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001297}
1298
Kailang Yangc9b58002007-10-16 14:30:01 +02001299/* unsolicited event for HP jack sensing */
1300static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1301{
1302 if (codec->vendor_id == 0x10ec0880)
1303 res >>= 28;
1304 else
1305 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001306 switch (res) {
1307 case ALC880_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +02001308 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001309 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001310 case ALC880_FRONT_EVENT:
1311 alc_line_automute(codec);
1312 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001313 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001314 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001315 break;
1316 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001317}
1318
1319static void alc_inithook(struct hda_codec *codec)
1320{
Takashi Iwaid922b512011-04-28 12:18:53 +02001321 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001322 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001323 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001324}
1325
Kailang Yangf9423e72008-05-27 12:32:25 +02001326/* additional initialization for ALC888 variants */
1327static void alc888_coef_init(struct hda_codec *codec)
1328{
1329 unsigned int tmp;
1330
1331 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1332 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1333 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001334 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001335 /* alc888S-VC */
1336 snd_hda_codec_read(codec, 0x20, 0,
1337 AC_VERB_SET_PROC_COEF, 0x830);
1338 else
1339 /* alc888-VB */
1340 snd_hda_codec_read(codec, 0x20, 0,
1341 AC_VERB_SET_PROC_COEF, 0x3030);
1342}
1343
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001344static void alc889_coef_init(struct hda_codec *codec)
1345{
1346 unsigned int tmp;
1347
1348 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1349 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1350 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1351 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1352}
1353
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001354/* turn on/off EAPD control (only if available) */
1355static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1356{
1357 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1358 return;
1359 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1360 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1361 on ? 2 : 0);
1362}
1363
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001364/* turn on/off EAPD controls of the codec */
1365static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
1366{
1367 /* We currently only handle front, HP */
1368 switch (codec->vendor_id) {
1369 case 0x10ec0260:
1370 set_eapd(codec, 0x0f, on);
1371 set_eapd(codec, 0x10, on);
1372 break;
1373 case 0x10ec0262:
1374 case 0x10ec0267:
1375 case 0x10ec0268:
1376 case 0x10ec0269:
1377 case 0x10ec0270:
1378 case 0x10ec0272:
1379 case 0x10ec0660:
1380 case 0x10ec0662:
1381 case 0x10ec0663:
1382 case 0x10ec0665:
1383 case 0x10ec0862:
1384 case 0x10ec0889:
1385 case 0x10ec0892:
1386 set_eapd(codec, 0x14, on);
1387 set_eapd(codec, 0x15, on);
1388 break;
1389 }
1390}
1391
Takashi Iwai1c716152011-04-07 10:37:16 +02001392/* generic shutup callback;
1393 * just turning off EPAD and a little pause for avoiding pop-noise
1394 */
1395static void alc_eapd_shutup(struct hda_codec *codec)
1396{
1397 alc_auto_setup_eapd(codec, false);
1398 msleep(200);
1399}
1400
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001401static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001402{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001403 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001404
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001405 switch (type) {
1406 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001407 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1408 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001409 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001410 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1411 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001412 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001413 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1414 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001415 case ALC_INIT_DEFAULT:
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001416 alc_auto_setup_eapd(codec, true);
Kailang Yangc9b58002007-10-16 14:30:01 +02001417 switch (codec->vendor_id) {
1418 case 0x10ec0260:
1419 snd_hda_codec_write(codec, 0x1a, 0,
1420 AC_VERB_SET_COEF_INDEX, 7);
1421 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1422 AC_VERB_GET_PROC_COEF, 0);
1423 snd_hda_codec_write(codec, 0x1a, 0,
1424 AC_VERB_SET_COEF_INDEX, 7);
1425 snd_hda_codec_write(codec, 0x1a, 0,
1426 AC_VERB_SET_PROC_COEF,
1427 tmp | 0x2010);
1428 break;
1429 case 0x10ec0262:
1430 case 0x10ec0880:
1431 case 0x10ec0882:
1432 case 0x10ec0883:
1433 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001434 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +01001435 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001436 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001437 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001438 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001439 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001440 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001441#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001442 case 0x10ec0267:
1443 case 0x10ec0268:
1444 snd_hda_codec_write(codec, 0x20, 0,
1445 AC_VERB_SET_COEF_INDEX, 7);
1446 tmp = snd_hda_codec_read(codec, 0x20, 0,
1447 AC_VERB_GET_PROC_COEF, 0);
1448 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001449 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001450 snd_hda_codec_write(codec, 0x20, 0,
1451 AC_VERB_SET_PROC_COEF,
1452 tmp | 0x3000);
1453 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001454#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001455 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001456 break;
1457 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001458}
Kailang Yangea1fb292008-08-26 12:58:38 +02001459
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001460static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
1461 struct snd_ctl_elem_info *uinfo)
1462{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001463 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1464 struct alc_spec *spec = codec->spec;
1465 static const char * const texts2[] = {
1466 "Disabled", "Enabled"
1467 };
1468 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001469 "Disabled", "Speaker Only", "Line-Out+Speaker"
1470 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001471 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001472
1473 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1474 uinfo->count = 1;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001475 if (spec->automute_hp_lo) {
1476 uinfo->value.enumerated.items = 3;
1477 texts = texts3;
1478 } else {
1479 uinfo->value.enumerated.items = 2;
1480 texts = texts2;
1481 }
1482 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1483 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001484 strcpy(uinfo->value.enumerated.name,
1485 texts[uinfo->value.enumerated.item]);
1486 return 0;
1487}
1488
1489static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
1490 struct snd_ctl_elem_value *ucontrol)
1491{
1492 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1493 struct alc_spec *spec = codec->spec;
1494 unsigned int val;
1495 if (!spec->automute)
1496 val = 0;
1497 else if (!spec->automute_lines)
1498 val = 1;
1499 else
1500 val = 2;
1501 ucontrol->value.enumerated.item[0] = val;
1502 return 0;
1503}
1504
1505static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
1506 struct snd_ctl_elem_value *ucontrol)
1507{
1508 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1509 struct alc_spec *spec = codec->spec;
1510
1511 switch (ucontrol->value.enumerated.item[0]) {
1512 case 0:
1513 if (!spec->automute)
1514 return 0;
1515 spec->automute = 0;
1516 break;
1517 case 1:
1518 if (spec->automute && !spec->automute_lines)
1519 return 0;
1520 spec->automute = 1;
1521 spec->automute_lines = 0;
1522 break;
1523 case 2:
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001524 if (!spec->automute_hp_lo)
1525 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001526 if (spec->automute && spec->automute_lines)
1527 return 0;
1528 spec->automute = 1;
1529 spec->automute_lines = 1;
1530 break;
1531 default:
1532 return -EINVAL;
1533 }
1534 update_speakers(codec);
1535 return 1;
1536}
1537
Takashi Iwaia9111322011-05-02 11:30:18 +02001538static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001539 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1540 .name = "Auto-Mute Mode",
1541 .info = alc_automute_mode_info,
1542 .get = alc_automute_mode_get,
1543 .put = alc_automute_mode_put,
1544};
1545
1546static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
1547
1548static int alc_add_automute_mode_enum(struct hda_codec *codec)
1549{
1550 struct alc_spec *spec = codec->spec;
1551 struct snd_kcontrol_new *knew;
1552
1553 knew = alc_kcontrol_new(spec);
1554 if (!knew)
1555 return -ENOMEM;
1556 *knew = alc_automute_mode_enum;
1557 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
1558 if (!knew->name)
1559 return -ENOMEM;
1560 return 0;
1561}
1562
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001563static void alc_init_auto_hp(struct hda_codec *codec)
1564{
1565 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001566 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001567 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001568 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001569
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001570 if (cfg->hp_pins[0])
1571 present++;
1572 if (cfg->line_out_pins[0])
1573 present++;
1574 if (cfg->speaker_pins[0])
1575 present++;
1576 if (present < 2) /* need two different output types */
1577 return;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001578 if (present == 3)
1579 spec->automute_hp_lo = 1; /* both HP and LO automute */
Kailang Yangc9b58002007-10-16 14:30:01 +02001580
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001581 if (!cfg->speaker_pins[0]) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001582 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1583 sizeof(cfg->speaker_pins));
1584 cfg->speaker_outs = cfg->line_outs;
1585 }
1586
1587 if (!cfg->hp_pins[0]) {
1588 memcpy(cfg->hp_pins, cfg->line_out_pins,
1589 sizeof(cfg->hp_pins));
1590 cfg->hp_outs = cfg->line_outs;
1591 }
1592
1593 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001594 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001595 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001596 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001597 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001598 nid);
1599 snd_hda_codec_write_cache(codec, nid, 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001600 AC_VERB_SET_UNSOLICITED_ENABLE,
1601 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaid922b512011-04-28 12:18:53 +02001602 spec->automute = 1;
1603 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001604 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001605 if (spec->automute && cfg->line_out_pins[0] &&
1606 cfg->line_out_pins[0] != cfg->hp_pins[0] &&
1607 cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
1608 for (i = 0; i < cfg->line_outs; i++) {
1609 hda_nid_t nid = cfg->line_out_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001610 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001611 continue;
1612 snd_printdd("realtek: Enable Line-Out auto-muting "
1613 "on NID 0x%x\n", nid);
1614 snd_hda_codec_write_cache(codec, nid, 0,
1615 AC_VERB_SET_UNSOLICITED_ENABLE,
1616 AC_USRSP_EN | ALC880_FRONT_EVENT);
1617 spec->detect_line = 1;
1618 }
Takashi Iwai52d3cb82011-05-17 10:04:08 +02001619 spec->automute_lines = spec->detect_line;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001620 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001621
1622 if (spec->automute) {
1623 /* create a control for automute mode */
1624 alc_add_automute_mode_enum(codec);
1625 spec->unsol_event = alc_sku_unsol_event;
1626 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001627}
1628
Takashi Iwai6c819492009-08-10 18:47:44 +02001629static void alc_init_auto_mic(struct hda_codec *codec)
1630{
1631 struct alc_spec *spec = codec->spec;
1632 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001633 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001634 int i;
1635
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001636 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001637 for (i = 0; i < cfg->num_inputs; i++) {
1638 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001639 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001640 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001641 switch (snd_hda_get_input_pin_attr(defcfg)) {
1642 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001643 if (fixed)
1644 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001645 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1646 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001647 fixed = nid;
1648 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001649 case INPUT_PIN_ATTR_UNUSED:
1650 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001651 case INPUT_PIN_ATTR_DOCK:
1652 if (dock)
1653 return; /* already occupied */
1654 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1655 return; /* invalid type */
1656 dock = nid;
1657 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001658 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001659 if (ext)
1660 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001661 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1662 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001663 ext = nid;
1664 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001665 }
1666 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001667 if (!ext && dock) {
1668 ext = dock;
1669 dock = 0;
1670 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001671 if (!ext || !fixed)
1672 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001673 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001674 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001675 if (dock && !is_jack_detectable(codec, dock))
1676 return; /* no unsol support */
1677 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1678 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001679 spec->ext_mic.pin = ext;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001680 spec->dock_mic.pin = dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001681 spec->int_mic.pin = fixed;
1682 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001683 spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai6c819492009-08-10 18:47:44 +02001684 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1685 spec->auto_mic = 1;
1686 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1687 AC_VERB_SET_UNSOLICITED_ENABLE,
1688 AC_USRSP_EN | ALC880_MIC_EVENT);
1689 spec->unsol_event = alc_sku_unsol_event;
1690}
1691
David Henningsson90622912010-10-14 14:50:18 +02001692/* Could be any non-zero and even value. When used as fixup, tells
1693 * the driver to ignore any present sku defines.
1694 */
1695#define ALC_FIXUP_SKU_IGNORE (2)
1696
Kailang Yangda00c242010-03-19 11:23:45 +01001697static int alc_auto_parse_customize_define(struct hda_codec *codec)
1698{
1699 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001700 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001701 struct alc_spec *spec = codec->spec;
1702
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001703 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1704
David Henningsson90622912010-10-14 14:50:18 +02001705 if (spec->cdefine.fixup) {
1706 ass = spec->cdefine.sku_cfg;
1707 if (ass == ALC_FIXUP_SKU_IGNORE)
1708 return -1;
1709 goto do_sku;
1710 }
1711
Kailang Yangda00c242010-03-19 11:23:45 +01001712 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001713 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001714 goto do_sku;
1715
1716 nid = 0x1d;
1717 if (codec->vendor_id == 0x10ec0260)
1718 nid = 0x17;
1719 ass = snd_hda_codec_get_pincfg(codec, nid);
1720
1721 if (!(ass & 1)) {
1722 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1723 codec->chip_name, ass);
1724 return -1;
1725 }
1726
1727 /* check sum */
1728 tmp = 0;
1729 for (i = 1; i < 16; i++) {
1730 if ((ass >> i) & 1)
1731 tmp++;
1732 }
1733 if (((ass >> 16) & 0xf) != tmp)
1734 return -1;
1735
1736 spec->cdefine.port_connectivity = ass >> 30;
1737 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1738 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1739 spec->cdefine.customization = ass >> 8;
1740do_sku:
1741 spec->cdefine.sku_cfg = ass;
1742 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1743 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1744 spec->cdefine.swap = (ass & 0x2) >> 1;
1745 spec->cdefine.override = ass & 0x1;
1746
1747 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1748 nid, spec->cdefine.sku_cfg);
1749 snd_printd("SKU: port_connectivity=0x%x\n",
1750 spec->cdefine.port_connectivity);
1751 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1752 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1753 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1754 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1755 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1756 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1757 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1758
1759 return 0;
1760}
1761
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001762/* check subsystem ID and set up device-specific initialization;
1763 * return 1 if initialized, 0 if invalid SSID
1764 */
1765/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1766 * 31 ~ 16 : Manufacture ID
1767 * 15 ~ 8 : SKU ID
1768 * 7 ~ 0 : Assembly ID
1769 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1770 */
1771static int alc_subsystem_id(struct hda_codec *codec,
1772 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001773 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001774{
1775 unsigned int ass, tmp, i;
1776 unsigned nid;
1777 struct alc_spec *spec = codec->spec;
1778
David Henningsson90622912010-10-14 14:50:18 +02001779 if (spec->cdefine.fixup) {
1780 ass = spec->cdefine.sku_cfg;
1781 if (ass == ALC_FIXUP_SKU_IGNORE)
1782 return 0;
1783 goto do_sku;
1784 }
1785
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001786 ass = codec->subsystem_id & 0xffff;
1787 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1788 goto do_sku;
1789
1790 /* invalid SSID, check the special NID pin defcfg instead */
1791 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001792 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001793 * 29~21 : reserve
1794 * 20 : PCBEEP input
1795 * 19~16 : Check sum (15:1)
1796 * 15~1 : Custom
1797 * 0 : override
1798 */
1799 nid = 0x1d;
1800 if (codec->vendor_id == 0x10ec0260)
1801 nid = 0x17;
1802 ass = snd_hda_codec_get_pincfg(codec, nid);
1803 snd_printd("realtek: No valid SSID, "
1804 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001805 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001806 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001807 return 0;
1808 if ((ass >> 30) != 1) /* no physical connection */
1809 return 0;
1810
1811 /* check sum */
1812 tmp = 0;
1813 for (i = 1; i < 16; i++) {
1814 if ((ass >> i) & 1)
1815 tmp++;
1816 }
1817 if (((ass >> 16) & 0xf) != tmp)
1818 return 0;
1819do_sku:
1820 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1821 ass & 0xffff, codec->vendor_id);
1822 /*
1823 * 0 : override
1824 * 1 : Swap Jack
1825 * 2 : 0 --> Desktop, 1 --> Laptop
1826 * 3~5 : External Amplifier control
1827 * 7~6 : Reserved
1828 */
1829 tmp = (ass & 0x38) >> 3; /* external Amp control */
1830 switch (tmp) {
1831 case 1:
1832 spec->init_amp = ALC_INIT_GPIO1;
1833 break;
1834 case 3:
1835 spec->init_amp = ALC_INIT_GPIO2;
1836 break;
1837 case 7:
1838 spec->init_amp = ALC_INIT_GPIO3;
1839 break;
1840 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001841 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001842 spec->init_amp = ALC_INIT_DEFAULT;
1843 break;
1844 }
1845
1846 /* is laptop or Desktop and enable the function "Mute internal speaker
1847 * when the external headphone out jack is plugged"
1848 */
1849 if (!(ass & 0x8000))
1850 return 1;
1851 /*
1852 * 10~8 : Jack location
1853 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1854 * 14~13: Resvered
1855 * 15 : 1 --> enable the function "Mute internal speaker
1856 * when the external headphone out jack is plugged"
1857 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001858 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001859 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001860 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1861 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001862 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001863 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001864 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001865 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001866 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001867 else if (tmp == 3)
1868 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001869 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001870 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001871 for (i = 0; i < spec->autocfg.line_outs; i++)
1872 if (spec->autocfg.line_out_pins[i] == nid)
1873 return 1;
1874 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001875 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001876 return 1;
1877}
Kailang Yangea1fb292008-08-26 12:58:38 +02001878
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001879static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001880 hda_nid_t porta, hda_nid_t porte,
1881 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001882{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001883 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001884 struct alc_spec *spec = codec->spec;
1885 snd_printd("realtek: "
1886 "Enable default setup for auto mode as fallback\n");
1887 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001888 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001889
1890 alc_init_auto_hp(codec);
1891 alc_init_auto_mic(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001892}
1893
Takashi Iwai41e41f12005-06-08 14:48:49 +02001894/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001895 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001896 */
1897
1898struct alc_pincfg {
1899 hda_nid_t nid;
1900 u32 val;
1901};
1902
Todd Broche1eb5f12010-12-06 11:19:51 -08001903struct alc_model_fixup {
1904 const int id;
1905 const char *name;
1906};
1907
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001908struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001909 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001910 bool chained;
1911 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001912 union {
1913 unsigned int sku;
1914 const struct alc_pincfg *pins;
1915 const struct hda_verb *verbs;
1916 void (*func)(struct hda_codec *codec,
1917 const struct alc_fixup *fix,
1918 int action);
1919 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001920};
1921
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001922enum {
1923 ALC_FIXUP_INVALID,
1924 ALC_FIXUP_SKU,
1925 ALC_FIXUP_PINS,
1926 ALC_FIXUP_VERBS,
1927 ALC_FIXUP_FUNC,
1928};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001929
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001930enum {
1931 ALC_FIXUP_ACT_PRE_PROBE,
1932 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001933 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001934};
1935
1936static void alc_apply_fixup(struct hda_codec *codec, int action)
1937{
1938 struct alc_spec *spec = codec->spec;
1939 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001940#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001941 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001942#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001943 int depth = 0;
1944
1945 if (!spec->fixup_list)
1946 return;
1947
1948 while (id >= 0) {
1949 const struct alc_fixup *fix = spec->fixup_list + id;
1950 const struct alc_pincfg *cfg;
1951
1952 switch (fix->type) {
1953 case ALC_FIXUP_SKU:
1954 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1955 break;;
1956 snd_printdd(KERN_INFO "hda_codec: %s: "
1957 "Apply sku override for %s\n",
1958 codec->chip_name, modelname);
1959 spec->cdefine.sku_cfg = fix->v.sku;
1960 spec->cdefine.fixup = 1;
1961 break;
1962 case ALC_FIXUP_PINS:
1963 cfg = fix->v.pins;
1964 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1965 break;
1966 snd_printdd(KERN_INFO "hda_codec: %s: "
1967 "Apply pincfg for %s\n",
1968 codec->chip_name, modelname);
1969 for (; cfg->nid; cfg++)
1970 snd_hda_codec_set_pincfg(codec, cfg->nid,
1971 cfg->val);
1972 break;
1973 case ALC_FIXUP_VERBS:
1974 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1975 break;
1976 snd_printdd(KERN_INFO "hda_codec: %s: "
1977 "Apply fix-verbs for %s\n",
1978 codec->chip_name, modelname);
1979 add_verb(codec->spec, fix->v.verbs);
1980 break;
1981 case ALC_FIXUP_FUNC:
1982 if (!fix->v.func)
1983 break;
1984 snd_printdd(KERN_INFO "hda_codec: %s: "
1985 "Apply fix-func for %s\n",
1986 codec->chip_name, modelname);
1987 fix->v.func(codec, fix, action);
1988 break;
1989 default:
1990 snd_printk(KERN_ERR "hda_codec: %s: "
1991 "Invalid fixup type %d\n",
1992 codec->chip_name, fix->type);
1993 break;
1994 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02001995 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001996 break;
1997 if (++depth > 10)
1998 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02001999 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01002000 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002001}
2002
Todd Broche1eb5f12010-12-06 11:19:51 -08002003static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002004 const struct alc_model_fixup *models,
2005 const struct snd_pci_quirk *quirk,
2006 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08002007{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002008 struct alc_spec *spec = codec->spec;
2009 int id = -1;
2010 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08002011
Todd Broche1eb5f12010-12-06 11:19:51 -08002012 if (codec->modelname && models) {
2013 while (models->name) {
2014 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002015 id = models->id;
2016 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002017 break;
2018 }
2019 models++;
2020 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002021 }
2022 if (id < 0) {
2023 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
2024 if (quirk) {
2025 id = quirk->value;
2026#ifdef CONFIG_SND_DEBUG_VERBOSE
2027 name = quirk->name;
2028#endif
2029 }
2030 }
2031
2032 spec->fixup_id = id;
2033 if (id >= 0) {
2034 spec->fixup_list = fixlist;
2035 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002036 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002037}
2038
Kailang Yang274693f2009-12-03 10:07:50 +01002039static int alc_read_coef_idx(struct hda_codec *codec,
2040 unsigned int coef_idx)
2041{
2042 unsigned int val;
2043 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2044 coef_idx);
2045 val = snd_hda_codec_read(codec, 0x20, 0,
2046 AC_VERB_GET_PROC_COEF, 0);
2047 return val;
2048}
2049
Kailang Yang977ddd62010-09-15 10:02:29 +02002050static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
2051 unsigned int coef_val)
2052{
2053 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2054 coef_idx);
2055 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
2056 coef_val);
2057}
2058
Takashi Iwai757899a2010-07-30 10:48:14 +02002059/* set right pin controls for digital I/O */
2060static void alc_auto_init_digital(struct hda_codec *codec)
2061{
2062 struct alc_spec *spec = codec->spec;
2063 int i;
2064 hda_nid_t pin;
2065
2066 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2067 pin = spec->autocfg.dig_out_pins[i];
2068 if (pin) {
2069 snd_hda_codec_write(codec, pin, 0,
2070 AC_VERB_SET_PIN_WIDGET_CONTROL,
2071 PIN_OUT);
2072 }
2073 }
2074 pin = spec->autocfg.dig_in_pin;
2075 if (pin)
2076 snd_hda_codec_write(codec, pin, 0,
2077 AC_VERB_SET_PIN_WIDGET_CONTROL,
2078 PIN_IN);
2079}
2080
2081/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
2082static void alc_auto_parse_digital(struct hda_codec *codec)
2083{
2084 struct alc_spec *spec = codec->spec;
2085 int i, err;
2086 hda_nid_t dig_nid;
2087
2088 /* support multiple SPDIFs; the secondary is set up as a slave */
2089 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2090 err = snd_hda_get_connections(codec,
2091 spec->autocfg.dig_out_pins[i],
2092 &dig_nid, 1);
2093 if (err < 0)
2094 continue;
2095 if (!i) {
2096 spec->multiout.dig_out_nid = dig_nid;
2097 spec->dig_out_type = spec->autocfg.dig_out_type[0];
2098 } else {
2099 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2100 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2101 break;
2102 spec->slave_dig_outs[i - 1] = dig_nid;
2103 }
2104 }
2105
2106 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02002107 dig_nid = codec->start_nid;
2108 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2109 unsigned int wcaps = get_wcaps(codec, dig_nid);
2110 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2111 continue;
2112 if (!(wcaps & AC_WCAP_DIGITAL))
2113 continue;
2114 if (!(wcaps & AC_WCAP_CONN_LIST))
2115 continue;
2116 err = get_connection_index(codec, dig_nid,
2117 spec->autocfg.dig_in_pin);
2118 if (err >= 0) {
2119 spec->dig_in_nid = dig_nid;
2120 break;
2121 }
2122 }
Takashi Iwai757899a2010-07-30 10:48:14 +02002123 }
2124}
2125
Takashi Iwaif95474e2007-07-10 00:47:43 +02002126/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002127 * ALC888
2128 */
2129
2130/*
2131 * 2ch mode
2132 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002133static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002134/* Mic-in jack as mic in */
2135 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2136 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2137/* Line-in jack as Line in */
2138 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2139 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2140/* Line-Out as Front */
2141 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2142 { } /* end */
2143};
2144
2145/*
2146 * 4ch mode
2147 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002148static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002149/* Mic-in jack as mic in */
2150 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2151 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2152/* Line-in jack as Surround */
2153 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2154 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2155/* Line-Out as Front */
2156 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2157 { } /* end */
2158};
2159
2160/*
2161 * 6ch mode
2162 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002163static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002164/* Mic-in jack as CLFE */
2165 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2166 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2167/* Line-in jack as Surround */
2168 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2169 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2170/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
2171 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2172 { } /* end */
2173};
2174
2175/*
2176 * 8ch mode
2177 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002178static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002179/* Mic-in jack as CLFE */
2180 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2181 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2182/* Line-in jack as Surround */
2183 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2184 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2185/* Line-Out as Side */
2186 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2187 { } /* end */
2188};
2189
Takashi Iwaia9111322011-05-02 11:30:18 +02002190static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002191 { 2, alc888_4ST_ch2_intel_init },
2192 { 4, alc888_4ST_ch4_intel_init },
2193 { 6, alc888_4ST_ch6_intel_init },
2194 { 8, alc888_4ST_ch8_intel_init },
2195};
2196
2197/*
2198 * ALC888 Fujitsu Siemens Amillo xa3530
2199 */
2200
Takashi Iwaia9111322011-05-02 11:30:18 +02002201static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002202/* Front Mic: set to PIN_IN (empty by default) */
2203 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2204/* Connect Internal HP to Front */
2205 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2206 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2207 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2208/* Connect Bass HP to Front */
2209 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2210 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2211 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2212/* Connect Line-Out side jack (SPDIF) to Side */
2213 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2214 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2215 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2216/* Connect Mic jack to CLFE */
2217 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2218 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2219 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
2220/* Connect Line-in jack to Surround */
2221 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2222 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2223 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
2224/* Connect HP out jack to Front */
2225 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2226 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2227 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2228/* Enable unsolicited event for HP jack and Line-out jack */
2229 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2230 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2231 {}
2232};
2233
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002234static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02002235{
2236 struct alc_spec *spec = codec->spec;
2237
2238 spec->autocfg.hp_pins[0] = 0x15;
2239 spec->autocfg.speaker_pins[0] = 0x14;
2240 spec->autocfg.speaker_pins[1] = 0x16;
2241 spec->autocfg.speaker_pins[2] = 0x17;
2242 spec->autocfg.speaker_pins[3] = 0x19;
2243 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02002244 spec->automute = 1;
2245 spec->automute_mode = ALC_AUTOMUTE_AMP;
Wu Fengguang6732bd02009-07-30 09:19:14 +02002246}
2247
2248static void alc889_intel_init_hook(struct hda_codec *codec)
2249{
2250 alc889_coef_init(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02002251 alc_hp_automute(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02002252}
2253
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002254static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002255{
2256 struct alc_spec *spec = codec->spec;
2257
2258 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2259 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2260 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2261 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaid922b512011-04-28 12:18:53 +02002262 spec->automute = 1;
2263 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002264}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002265
2266/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002267 * ALC888 Acer Aspire 4930G model
2268 */
2269
Takashi Iwaia9111322011-05-02 11:30:18 +02002270static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002271/* Front Mic: set to PIN_IN (empty by default) */
2272 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2273/* Unselect Front Mic by default in input mixer 3 */
2274 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002275/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002276 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2277/* Connect Internal HP to front */
2278 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2279 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2280 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2281/* Connect HP out to front */
2282 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2283 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2284 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie2e93292011-01-12 08:03:39 +01002285 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002286 { }
2287};
2288
Hector Martin3b315d72009-06-02 10:54:19 +02002289/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002290 * ALC888 Acer Aspire 6530G model
2291 */
2292
Takashi Iwaia9111322011-05-02 11:30:18 +02002293static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002294/* Route to built-in subwoofer as well as speakers */
2295 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2296 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2297 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2298 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002299/* Bias voltage on for external mic port */
2300 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002301/* Front Mic: set to PIN_IN (empty by default) */
2302 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2303/* Unselect Front Mic by default in input mixer 3 */
2304 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002305/* Enable unsolicited event for HP jack */
2306 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2307/* Enable speaker output */
2308 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2309 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002310 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002311/* Enable headphone output */
2312 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2313 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2314 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002315 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002316 { }
2317};
2318
2319/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002320 *ALC888 Acer Aspire 7730G model
2321 */
2322
Takashi Iwaia9111322011-05-02 11:30:18 +02002323static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002324/* Bias voltage on for external mic port */
2325 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2326/* Front Mic: set to PIN_IN (empty by default) */
2327 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2328/* Unselect Front Mic by default in input mixer 3 */
2329 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2330/* Enable unsolicited event for HP jack */
2331 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2332/* Enable speaker output */
2333 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2334 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2335 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2336/* Enable headphone output */
2337 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2338 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2339 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2340 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2341/*Enable internal subwoofer */
2342 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2343 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2344 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2345 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2346 { }
2347};
2348
2349/*
Hector Martin018df412009-06-04 00:13:40 +02002350 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002351 */
2352
Takashi Iwaia9111322011-05-02 11:30:18 +02002353static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002354/* Front Mic: set to PIN_IN (empty by default) */
2355 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2356/* Unselect Front Mic by default in input mixer 3 */
2357 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2358/* Enable unsolicited event for HP jack */
2359 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2360/* Connect Internal Front to Front */
2361 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2362 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2363 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2364/* Connect Internal Rear to Rear */
2365 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2366 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2367 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2368/* Connect Internal CLFE to CLFE */
2369 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2370 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2371 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2372/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002373 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002374 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2375 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2376/* Enable all DACs */
2377/* DAC DISABLE/MUTE 1? */
2378/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2379 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2380 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2381/* DAC DISABLE/MUTE 2? */
2382/* some bit here disables the other DACs. Init=0x4900 */
2383 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2384 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002385/* DMIC fix
2386 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2387 * which makes the stereo useless. However, either the mic or the ALC889
2388 * makes the signal become a difference/sum signal instead of standard
2389 * stereo, which is annoying. So instead we flip this bit which makes the
2390 * codec replicate the sum signal to both channels, turning it into a
2391 * normal mono mic.
2392 */
2393/* DMIC_CONTROL? Init value = 0x0001 */
2394 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2395 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002396 { }
2397};
2398
Takashi Iwaia9111322011-05-02 11:30:18 +02002399static const struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002400 /* Front mic only available on one ADC */
2401 {
2402 .num_items = 4,
2403 .items = {
2404 { "Mic", 0x0 },
2405 { "Line", 0x2 },
2406 { "CD", 0x4 },
2407 { "Front Mic", 0xb },
2408 },
2409 },
2410 {
2411 .num_items = 3,
2412 .items = {
2413 { "Mic", 0x0 },
2414 { "Line", 0x2 },
2415 { "CD", 0x4 },
2416 },
2417 }
2418};
2419
Takashi Iwaia9111322011-05-02 11:30:18 +02002420static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01002421 /* Interal mic only available on one ADC */
2422 {
Tony Vroon684a8842009-06-26 09:27:50 +01002423 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002424 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002425 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002426 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002427 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002428 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002429 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002430 },
2431 },
2432 {
Tony Vroon684a8842009-06-26 09:27:50 +01002433 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002434 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002435 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002436 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002437 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002438 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002439 },
2440 }
2441};
2442
Takashi Iwaia9111322011-05-02 11:30:18 +02002443static const struct hda_input_mux alc889_capture_sources[3] = {
Hector Martin018df412009-06-04 00:13:40 +02002444 /* Digital mic only available on first "ADC" */
2445 {
2446 .num_items = 5,
2447 .items = {
2448 { "Mic", 0x0 },
2449 { "Line", 0x2 },
2450 { "CD", 0x4 },
2451 { "Front Mic", 0xb },
2452 { "Input Mix", 0xa },
2453 },
2454 },
2455 {
2456 .num_items = 4,
2457 .items = {
2458 { "Mic", 0x0 },
2459 { "Line", 0x2 },
2460 { "CD", 0x4 },
2461 { "Input Mix", 0xa },
2462 },
2463 },
2464 {
2465 .num_items = 4,
2466 .items = {
2467 { "Mic", 0x0 },
2468 { "Line", 0x2 },
2469 { "CD", 0x4 },
2470 { "Input Mix", 0xa },
2471 },
2472 }
2473};
2474
Takashi Iwaia9111322011-05-02 11:30:18 +02002475static const struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002476 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2477 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2478 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2479 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2480 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2481 HDA_OUTPUT),
2482 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2483 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2484 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2485 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2486 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2487 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2488 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2489 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2490 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2491 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002492 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002493 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002494 { } /* end */
2495};
2496
Takashi Iwaia9111322011-05-02 11:30:18 +02002497static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002498 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2499 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2500 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2501 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002502 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002503 HDA_OUTPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002504 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2505 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2506 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2507 HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
2508 HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002509 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2510 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2511 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2512 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2513 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2514 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
2515 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2516 { } /* end */
2517};
2518
Takashi Iwaia9111322011-05-02 11:30:18 +02002519static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
Hector Martin556eea92009-12-20 22:51:23 +01002520 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2521 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2522 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2523 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2524 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2525 HDA_OUTPUT),
2526 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2527 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2528 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2529 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2530 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2531 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002532 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002533 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2534 { } /* end */
2535};
2536
2537
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002538static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002539{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002540 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002541
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002542 spec->autocfg.hp_pins[0] = 0x15;
2543 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002544 spec->autocfg.speaker_pins[1] = 0x16;
2545 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002546 spec->automute = 1;
2547 spec->automute_mode = ALC_AUTOMUTE_AMP;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002548}
2549
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002550static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002551{
2552 struct alc_spec *spec = codec->spec;
2553
2554 spec->autocfg.hp_pins[0] = 0x15;
2555 spec->autocfg.speaker_pins[0] = 0x14;
2556 spec->autocfg.speaker_pins[1] = 0x16;
2557 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002558 spec->automute = 1;
2559 spec->automute_mode = ALC_AUTOMUTE_AMP;
Emilio López320d5922009-06-25 08:18:44 +02002560}
2561
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002562static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2563{
2564 struct alc_spec *spec = codec->spec;
2565
2566 spec->autocfg.hp_pins[0] = 0x15;
2567 spec->autocfg.speaker_pins[0] = 0x14;
2568 spec->autocfg.speaker_pins[1] = 0x16;
2569 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002570 spec->automute = 1;
2571 spec->automute_mode = ALC_AUTOMUTE_AMP;
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002572}
2573
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002574static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002575{
2576 struct alc_spec *spec = codec->spec;
2577
2578 spec->autocfg.hp_pins[0] = 0x15;
2579 spec->autocfg.speaker_pins[0] = 0x14;
2580 spec->autocfg.speaker_pins[1] = 0x16;
2581 spec->autocfg.speaker_pins[2] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02002582 spec->automute = 1;
2583 spec->automute_mode = ALC_AUTOMUTE_AMP;
Hector Martin3b315d72009-06-02 10:54:19 +02002584}
2585
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002586/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002587 * ALC880 3-stack model
2588 *
2589 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002590 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2591 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 */
2593
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002594static const hda_nid_t alc880_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002595 /* front, rear, clfe, rear_surr */
2596 0x02, 0x05, 0x04, 0x03
2597};
2598
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002599static const hda_nid_t alc880_adc_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002600 /* ADC0-2 */
2601 0x07, 0x08, 0x09,
2602};
2603
2604/* The datasheet says the node 0x07 is connected from inputs,
2605 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002606 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002608static const hda_nid_t alc880_adc_nids_alt[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002609 /* ADC1-2 */
2610 0x08, 0x09,
2611};
2612
2613#define ALC880_DIGOUT_NID 0x06
2614#define ALC880_DIGIN_NID 0x0a
2615
Takashi Iwaia9111322011-05-02 11:30:18 +02002616static const struct hda_input_mux alc880_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002617 .num_items = 4,
2618 .items = {
2619 { "Mic", 0x0 },
2620 { "Front Mic", 0x3 },
2621 { "Line", 0x2 },
2622 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002624};
2625
2626/* channel source setting (2/6 channel selection for 3-stack) */
2627/* 2ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002628static const struct hda_verb alc880_threestack_ch2_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002629 /* set line-in to input, mute it */
2630 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2631 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2632 /* set mic-in to input vref 80%, mute it */
2633 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2634 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 { } /* end */
2636};
2637
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002638/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002639static const struct hda_verb alc880_threestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002640 /* set line-in to output, unmute it */
2641 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2642 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2643 /* set mic-in to output, unmute it */
2644 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2645 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2646 { } /* end */
2647};
2648
Takashi Iwaia9111322011-05-02 11:30:18 +02002649static const struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002650 { 2, alc880_threestack_ch2_init },
2651 { 6, alc880_threestack_ch6_init },
2652};
2653
Takashi Iwaia9111322011-05-02 11:30:18 +02002654static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002655 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002656 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002657 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002658 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002659 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2660 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002661 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2662 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2664 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2665 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2666 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2667 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2668 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2669 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2670 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002672 {
2673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2674 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002675 .info = alc_ch_mode_info,
2676 .get = alc_ch_mode_get,
2677 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002678 },
2679 { } /* end */
2680};
2681
2682/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002683static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2684 struct snd_ctl_elem_info *uinfo)
2685{
2686 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2687 struct alc_spec *spec = codec->spec;
2688 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002689
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002690 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002691 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2692 HDA_INPUT);
2693 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002694 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002695 return err;
2696}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002698static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2699 unsigned int size, unsigned int __user *tlv)
2700{
2701 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2702 struct alc_spec *spec = codec->spec;
2703 int err;
2704
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002705 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002706 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2707 HDA_INPUT);
2708 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002709 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002710 return err;
2711}
2712
2713typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2714 struct snd_ctl_elem_value *ucontrol);
2715
2716static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2717 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002718 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002719{
2720 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2721 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002722 int i, err;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002723
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002724 mutex_lock(&codec->control_mutex);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002725 if (check_adc_switch && spec->dual_adc_switch) {
2726 for (i = 0; i < spec->num_adc_nids; i++) {
2727 kcontrol->private_value =
2728 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2729 3, 0, HDA_INPUT);
2730 err = func(kcontrol, ucontrol);
2731 if (err < 0)
2732 goto error;
2733 }
2734 } else {
2735 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2736 kcontrol->private_value =
2737 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2738 3, 0, HDA_INPUT);
2739 err = func(kcontrol, ucontrol);
2740 }
2741 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002742 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002743 return err;
2744}
2745
2746static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2747 struct snd_ctl_elem_value *ucontrol)
2748{
2749 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002750 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002751}
2752
2753static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2754 struct snd_ctl_elem_value *ucontrol)
2755{
2756 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002757 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002758}
2759
2760/* capture mixer elements */
2761#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2762
2763static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2764 struct snd_ctl_elem_value *ucontrol)
2765{
2766 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002767 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002768}
2769
2770static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2771 struct snd_ctl_elem_value *ucontrol)
2772{
2773 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002774 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002775}
2776
Takashi Iwaia23b6882009-03-23 15:21:36 +01002777#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002778 { \
2779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2780 .name = "Capture Switch", \
2781 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2782 .count = num, \
2783 .info = alc_cap_sw_info, \
2784 .get = alc_cap_sw_get, \
2785 .put = alc_cap_sw_put, \
2786 }, \
2787 { \
2788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2789 .name = "Capture Volume", \
2790 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2791 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2792 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2793 .count = num, \
2794 .info = alc_cap_vol_info, \
2795 .get = alc_cap_vol_get, \
2796 .put = alc_cap_vol_put, \
2797 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002798 }
2799
2800#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002801 { \
2802 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2803 /* .name = "Capture Source", */ \
2804 .name = "Input Source", \
2805 .count = num, \
2806 .info = alc_mux_enum_info, \
2807 .get = alc_mux_enum_get, \
2808 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002809 }
2810
2811#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002812static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002813 _DEFINE_CAPMIX(num), \
2814 _DEFINE_CAPSRC(num), \
2815 { } /* end */ \
2816}
2817
2818#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002819static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002820 _DEFINE_CAPMIX(num), \
2821 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002822}
2823
2824/* up to three ADCs */
2825DEFINE_CAPMIX(1);
2826DEFINE_CAPMIX(2);
2827DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002828DEFINE_CAPMIX_NOSRC(1);
2829DEFINE_CAPMIX_NOSRC(2);
2830DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002831
2832/*
2833 * ALC880 5-stack model
2834 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002835 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2836 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002837 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2838 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2839 */
2840
2841/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02002842static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002843 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002844 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 { } /* end */
2846};
2847
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002848/* channel source setting (6/8 channel selection for 5-stack) */
2849/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002850static const struct hda_verb alc880_fivestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002851 /* set line-in to input, mute it */
2852 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2853 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002854 { } /* end */
2855};
2856
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002857/* 8ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002858static const struct hda_verb alc880_fivestack_ch8_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002859 /* set line-in to output, unmute it */
2860 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2861 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2862 { } /* end */
2863};
2864
Takashi Iwaia9111322011-05-02 11:30:18 +02002865static const struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002866 { 6, alc880_fivestack_ch6_init },
2867 { 8, alc880_fivestack_ch8_init },
2868};
2869
2870
2871/*
2872 * ALC880 6-stack model
2873 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002874 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2875 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002876 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2877 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2878 */
2879
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002880static const hda_nid_t alc880_6st_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002881 /* front, rear, clfe, rear_surr */
2882 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002883};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002884
Takashi Iwaia9111322011-05-02 11:30:18 +02002885static const struct hda_input_mux alc880_6stack_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002886 .num_items = 4,
2887 .items = {
2888 { "Mic", 0x0 },
2889 { "Front Mic", 0x1 },
2890 { "Line", 0x2 },
2891 { "CD", 0x4 },
2892 },
2893};
2894
2895/* fixed 8-channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002896static const struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002897 { 8, NULL },
2898};
2899
Takashi Iwaia9111322011-05-02 11:30:18 +02002900static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002901 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002902 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002903 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002904 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002905 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2906 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002907 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2908 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002909 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002910 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002911 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2912 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2913 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2914 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2915 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2916 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2917 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2918 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002919 {
2920 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2921 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002922 .info = alc_ch_mode_info,
2923 .get = alc_ch_mode_get,
2924 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002925 },
2926 { } /* end */
2927};
2928
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002929
2930/*
2931 * ALC880 W810 model
2932 *
2933 * W810 has rear IO for:
2934 * Front (DAC 02)
2935 * Surround (DAC 03)
2936 * Center/LFE (DAC 04)
2937 * Digital out (06)
2938 *
2939 * The system also has a pair of internal speakers, and a headphone jack.
2940 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002941 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002942 * There is a variable resistor to control the speaker or headphone
2943 * volume. This is a hardware-only device without a software API.
2944 *
2945 * Plugging headphones in will disable the internal speakers. This is
2946 * implemented in hardware, not via the driver using jack sense. In
2947 * a similar fashion, plugging into the rear socket marked "front" will
2948 * disable both the speakers and headphones.
2949 *
2950 * For input, there's a microphone jack, and an "audio in" jack.
2951 * These may not do anything useful with this driver yet, because I
2952 * haven't setup any initialization verbs for these yet...
2953 */
2954
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002955static const hda_nid_t alc880_w810_dac_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002956 /* front, rear/surround, clfe */
2957 0x02, 0x03, 0x04
2958};
2959
2960/* fixed 6 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002961static const struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002962 { 6, NULL }
2963};
2964
2965/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaia9111322011-05-02 11:30:18 +02002966static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002967 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002968 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002969 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002970 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002971 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2972 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002973 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2974 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002975 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2976 { } /* end */
2977};
2978
2979
2980/*
2981 * Z710V model
2982 *
2983 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002984 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2985 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002986 */
2987
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002988static const hda_nid_t alc880_z71v_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002989 0x02
2990};
2991#define ALC880_Z71V_HP_DAC 0x03
2992
2993/* fixed 2 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002994static const struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002995 { 2, NULL }
2996};
2997
Takashi Iwaia9111322011-05-02 11:30:18 +02002998static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002999 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003000 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003001 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003002 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003003 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3004 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3005 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3006 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3007 { } /* end */
3008};
3009
3010
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003011/*
3012 * ALC880 F1734 model
3013 *
3014 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
3015 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
3016 */
3017
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003018static const hda_nid_t alc880_f1734_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003019 0x03
3020};
3021#define ALC880_F1734_HP_DAC 0x02
3022
Takashi Iwaia9111322011-05-02 11:30:18 +02003023static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003024 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003025 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01003026 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3027 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003028 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3029 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01003030 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3031 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003032 { } /* end */
3033};
3034
Takashi Iwaia9111322011-05-02 11:30:18 +02003035static const struct hda_input_mux alc880_f1734_capture_source = {
Takashi Iwai937b4162008-02-11 14:52:36 +01003036 .num_items = 2,
3037 .items = {
3038 { "Mic", 0x1 },
3039 { "CD", 0x4 },
3040 },
3041};
3042
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003043
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003044/*
3045 * ALC880 ASUS model
3046 *
3047 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3048 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3049 * Mic = 0x18, Line = 0x1a
3050 */
3051
3052#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
3053#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
3054
Takashi Iwaia9111322011-05-02 11:30:18 +02003055static const struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003056 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003057 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003058 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003059 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003060 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3061 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003062 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3063 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003064 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3065 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3066 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3067 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3068 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3069 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003070 {
3071 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3072 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003073 .info = alc_ch_mode_info,
3074 .get = alc_ch_mode_get,
3075 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02003076 },
3077 { } /* end */
3078};
3079
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003080/*
3081 * ALC880 ASUS W1V model
3082 *
3083 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3084 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3085 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
3086 */
3087
3088/* additional mixers to alc880_asus_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02003089static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003090 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
3091 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003092 { } /* end */
3093};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003094
Kailang Yangdf694da2005-12-05 19:42:22 +01003095/* TCL S700 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003096static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003097 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3098 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3099 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
3100 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
3101 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
3102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
3103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
3104 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3105 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003106 { } /* end */
3107};
3108
Kailang Yangccc656c2006-10-17 12:32:26 +02003109/* Uniwill */
Takashi Iwaia9111322011-05-02 11:30:18 +02003110static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003111 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3112 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3113 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3114 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003115 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3116 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3117 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3118 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3119 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3120 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3121 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3122 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3123 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3124 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3125 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3126 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003127 {
3128 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3129 .name = "Channel Mode",
3130 .info = alc_ch_mode_info,
3131 .get = alc_ch_mode_get,
3132 .put = alc_ch_mode_put,
3133 },
3134 { } /* end */
3135};
3136
Takashi Iwaia9111322011-05-02 11:30:18 +02003137static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003138 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3139 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3140 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3141 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
3142 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3143 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01003144 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3145 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01003146 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3147 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003148 { } /* end */
3149};
3150
Takashi Iwaia9111322011-05-02 11:30:18 +02003151static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003152 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3153 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3154 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3155 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003156 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3157 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3158 { } /* end */
3159};
3160
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01003162 * virtual master controls
3163 */
3164
3165/*
3166 * slave controls for virtual master
3167 */
Takashi Iwaiea734962011-01-17 11:29:34 +01003168static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003169 "Front Playback Volume",
3170 "Surround Playback Volume",
3171 "Center Playback Volume",
3172 "LFE Playback Volume",
3173 "Side Playback Volume",
3174 "Headphone Playback Volume",
3175 "Speaker Playback Volume",
3176 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003177 "Line-Out Playback Volume",
3178 NULL,
3179};
3180
Takashi Iwaiea734962011-01-17 11:29:34 +01003181static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003182 "Front Playback Switch",
3183 "Surround Playback Switch",
3184 "Center Playback Switch",
3185 "LFE Playback Switch",
3186 "Side Playback Switch",
3187 "Headphone Playback Switch",
3188 "Speaker Playback Switch",
3189 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01003190 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01003191 "Line-Out Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003192 NULL,
3193};
3194
3195/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003196 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 */
Takashi Iwai603c4012008-07-30 15:01:44 +02003198
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003199#define NID_MAPPING (-1)
3200
3201#define SUBDEV_SPEAKER_ (0 << 6)
3202#define SUBDEV_HP_ (1 << 6)
3203#define SUBDEV_LINE_ (2 << 6)
3204#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
3205#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
3206#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
3207
Takashi Iwai603c4012008-07-30 15:01:44 +02003208static void alc_free_kctls(struct hda_codec *codec);
3209
Takashi Iwai67d634c2009-11-16 15:35:59 +01003210#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003211/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02003212static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003213 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003214 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003215 { } /* end */
3216};
Takashi Iwai67d634c2009-11-16 15:35:59 +01003217#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003218
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219static int alc_build_controls(struct hda_codec *codec)
3220{
3221 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02003222 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02003223 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003224 int i, j, err;
3225 unsigned int u;
3226 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
3228 for (i = 0; i < spec->num_mixers; i++) {
3229 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
3230 if (err < 0)
3231 return err;
3232 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003233 if (spec->cap_mixer) {
3234 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
3235 if (err < 0)
3236 return err;
3237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003239 err = snd_hda_create_spdif_out_ctls(codec,
3240 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 if (err < 0)
3242 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003243 if (!spec->no_analog) {
3244 err = snd_hda_create_spdif_share_sw(codec,
3245 &spec->multiout);
3246 if (err < 0)
3247 return err;
3248 spec->multiout.share_spdif = 1;
3249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 }
3251 if (spec->dig_in_nid) {
3252 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3253 if (err < 0)
3254 return err;
3255 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003256
Takashi Iwai67d634c2009-11-16 15:35:59 +01003257#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003258 /* create beep controls if needed */
3259 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02003260 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003261 for (knew = alc_beep_mixer; knew->name; knew++) {
3262 struct snd_kcontrol *kctl;
3263 kctl = snd_ctl_new1(knew, codec);
3264 if (!kctl)
3265 return -ENOMEM;
3266 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003267 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003268 if (err < 0)
3269 return err;
3270 }
3271 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003272#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003273
Takashi Iwai2134ea42008-01-10 16:53:55 +01003274 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003275 if (!spec->no_analog &&
3276 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003277 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003278 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003279 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003280 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003281 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003282 if (err < 0)
3283 return err;
3284 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003285 if (!spec->no_analog &&
3286 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003287 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3288 NULL, alc_slave_sws);
3289 if (err < 0)
3290 return err;
3291 }
3292
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003293 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003294 if (spec->capsrc_nids || spec->adc_nids) {
3295 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3296 if (!kctl)
3297 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3298 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003299 const hda_nid_t *nids = spec->capsrc_nids;
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003300 if (!nids)
3301 nids = spec->adc_nids;
3302 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3303 if (err < 0)
3304 return err;
3305 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003306 }
3307 if (spec->cap_mixer) {
3308 const char *kname = kctl ? kctl->id.name : NULL;
3309 for (knew = spec->cap_mixer; knew->name; knew++) {
3310 if (kname && strcmp(knew->name, kname) == 0)
3311 continue;
3312 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3313 for (i = 0; kctl && i < kctl->count; i++) {
3314 err = snd_hda_add_nid(codec, kctl, i,
3315 spec->adc_nids[i]);
3316 if (err < 0)
3317 return err;
3318 }
3319 }
3320 }
3321
3322 /* other nid->control mapping */
3323 for (i = 0; i < spec->num_mixers; i++) {
3324 for (knew = spec->mixers[i]; knew->name; knew++) {
3325 if (knew->iface != NID_MAPPING)
3326 continue;
3327 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3328 if (kctl == NULL)
3329 continue;
3330 u = knew->subdevice;
3331 for (j = 0; j < 4; j++, u >>= 8) {
3332 nid = u & 0x3f;
3333 if (nid == 0)
3334 continue;
3335 switch (u & 0xc0) {
3336 case SUBDEV_SPEAKER_:
3337 nid = spec->autocfg.speaker_pins[nid];
3338 break;
3339 case SUBDEV_LINE_:
3340 nid = spec->autocfg.line_out_pins[nid];
3341 break;
3342 case SUBDEV_HP_:
3343 nid = spec->autocfg.hp_pins[nid];
3344 break;
3345 default:
3346 continue;
3347 }
3348 err = snd_hda_add_nid(codec, kctl, 0, nid);
3349 if (err < 0)
3350 return err;
3351 }
3352 u = knew->private_value;
3353 for (j = 0; j < 4; j++, u >>= 8) {
3354 nid = u & 0xff;
3355 if (nid == 0)
3356 continue;
3357 err = snd_hda_add_nid(codec, kctl, 0, nid);
3358 if (err < 0)
3359 return err;
3360 }
3361 }
3362 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003363
3364 alc_free_kctls(codec); /* no longer needed */
3365
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 return 0;
3367}
3368
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003369
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370/*
3371 * initialize the codec volumes, etc
3372 */
3373
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003374/*
3375 * generic initialization of ADC, input mixers and output mixers
3376 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003377static const struct hda_verb alc880_volume_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003378 /*
3379 * Unmute ADC0-2 and set the default input to mic-in
3380 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003381 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003382 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003383 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003384 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003385 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003386 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003388 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3389 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003390 * Note: PASD motherboards uses the Line In 2 as the input for front
3391 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003393 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003394 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3395 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3396 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3397 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3398 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3399 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3400 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003402 /*
3403 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003405 /* set vol=0 to output mixers */
3406 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3407 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3408 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3409 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3410 /* set up input amps for analog loopback */
3411 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003412 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3413 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003414 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3415 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003416 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3417 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003418 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3419 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
3421 { }
3422};
3423
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424/*
3425 * 3-stack pin configuration:
3426 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3427 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003428static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003429 /*
3430 * preset connection lists of input pins
3431 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3432 */
3433 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3434 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3435 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3436
3437 /*
3438 * Set pin mode and muting
3439 */
3440 /* set front pin widgets 0x14 for output */
3441 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3442 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3443 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3444 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3445 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3446 /* Mic2 (as headphone out) for HP output */
3447 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3448 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3449 /* Line In pin widget for input */
3450 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3451 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3452 /* Line2 (as front mic) pin widget for input and vref at 80% */
3453 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3454 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3455 /* CD pin widget for input */
3456 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3457
3458 { }
3459};
3460
3461/*
3462 * 5-stack pin configuration:
3463 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3464 * line-in/side = 0x1a, f-mic = 0x1b
3465 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003466static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003467 /*
3468 * preset connection lists of input pins
3469 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3470 */
3471 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3472 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3473
3474 /*
3475 * Set pin mode and muting
3476 */
3477 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003478 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3479 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3480 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3481 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003482 /* unmute pins for output (no gain on this amp) */
3483 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3484 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3485 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3486 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3487
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003489 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003490 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3491 /* Mic2 (as headphone out) for HP output */
3492 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003493 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003494 /* Line In pin widget for input */
3495 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3496 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3497 /* Line2 (as front mic) pin widget for input and vref at 80% */
3498 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3499 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3500 /* CD pin widget for input */
3501 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
3503 { }
3504};
3505
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003506/*
3507 * W810 pin configuration:
3508 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3509 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003510static const struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 /* hphone/speaker input selector: front DAC */
3512 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3513
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003514 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3515 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3516 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3517 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3518 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3519 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3520
3521 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003522 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 { }
3525};
3526
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003527/*
3528 * Z71V pin configuration:
3529 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3530 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003531static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003532 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003533 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003534 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003535 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003536
Takashi Iwai16ded522005-06-10 19:58:24 +02003537 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003538 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003539 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003540 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003541
3542 { }
3543};
3544
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003545/*
3546 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003547 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3548 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003549 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003550static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003551 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3552
Takashi Iwai16ded522005-06-10 19:58:24 +02003553 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003554 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003555 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003556 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003557 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003558 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003559 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003560 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3561
Takashi Iwai16ded522005-06-10 19:58:24 +02003562 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003563 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003564 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003565 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003566 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003567 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003568 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003569 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003570 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003571
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003572 { }
3573};
Takashi Iwai16ded522005-06-10 19:58:24 +02003574
Kailang Yangccc656c2006-10-17 12:32:26 +02003575/*
3576 * Uniwill pin configuration:
3577 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3578 * line = 0x1a
3579 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003580static const struct hda_verb alc880_uniwill_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003581 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3582
3583 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3584 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3585 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3586 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3587 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3588 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3589 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3590 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3592 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3593 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3594 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3595 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3596 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3597
3598 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3599 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3600 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3601 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3602 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3603 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3604 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3605 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3606 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3607
3608 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3609 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3610
3611 { }
3612};
3613
3614/*
3615* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003616* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003617 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003618static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003619 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3620
3621 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3622 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3623 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3625 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3626 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3627 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3628 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3629 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3630 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3631 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3632 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3633
3634 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3635 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3636 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3637 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3638 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3639 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3640
3641 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3642 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3643
3644 { }
3645};
3646
Takashi Iwaia9111322011-05-02 11:30:18 +02003647static const struct hda_verb alc880_beep_init_verbs[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003648 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3649 { }
3650};
3651
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003652/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003653static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003654{
3655 unsigned int present;
3656 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003657
Wu Fengguang864f92b2009-11-18 12:38:02 +08003658 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003659 bits = present ? HDA_AMP_MUTE : 0;
3660 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003661}
3662
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003663static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003664{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003665 struct alc_spec *spec = codec->spec;
3666
3667 spec->autocfg.hp_pins[0] = 0x14;
3668 spec->autocfg.speaker_pins[0] = 0x15;
3669 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02003670 spec->automute = 1;
3671 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003672}
3673
3674static void alc880_uniwill_init_hook(struct hda_codec *codec)
3675{
Takashi Iwaid922b512011-04-28 12:18:53 +02003676 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003677 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003678}
3679
3680static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3681 unsigned int res)
3682{
3683 /* Looks like the unsol event is incompatible with the standard
3684 * definition. 4bit tag is placed at 28 bit!
3685 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003686 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003687 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003688 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003689 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003690 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02003691 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003692 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003693 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003694}
3695
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003696static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003697{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003698 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003699
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003700 spec->autocfg.hp_pins[0] = 0x14;
3701 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02003702 spec->automute = 1;
3703 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangccc656c2006-10-17 12:32:26 +02003704}
3705
3706static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3707{
3708 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003709
Kailang Yangccc656c2006-10-17 12:32:26 +02003710 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003711 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3712 present &= HDA_AMP_VOLMASK;
3713 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3714 HDA_AMP_VOLMASK, present);
3715 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3716 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003717}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003718
Kailang Yangccc656c2006-10-17 12:32:26 +02003719static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3720 unsigned int res)
3721{
3722 /* Looks like the unsol event is incompatible with the standard
3723 * definition. 4bit tag is placed at 28 bit!
3724 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003725 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003726 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003727 else
Takashi Iwaid922b512011-04-28 12:18:53 +02003728 alc_sku_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003729}
3730
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003731/*
3732 * F1734 pin configuration:
3733 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3734 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003735static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003736 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003737 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3738 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3739 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3740 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3741
3742 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3743 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3744 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3745 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3746
3747 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3748 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003749 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003750 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3751 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3752 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3753 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3754 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3755 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003756
Takashi Iwai937b4162008-02-11 14:52:36 +01003757 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3758 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3759
Takashi Iwai16ded522005-06-10 19:58:24 +02003760 { }
3761};
3762
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003763/*
3764 * ASUS pin configuration:
3765 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3766 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003767static const struct hda_verb alc880_pin_asus_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003768 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3769 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3770 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3771 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3772
3773 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3774 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3775 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3776 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3777 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3778 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3779 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3780 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3781
3782 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3783 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3784 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3786 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3787 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3788 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3789 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3790 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003791
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003792 { }
3793};
3794
3795/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003796#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3797#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003798#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003799
Kailang Yangdf694da2005-12-05 19:42:22 +01003800/* Clevo m520g init */
Takashi Iwaia9111322011-05-02 11:30:18 +02003801static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003802 /* headphone output */
3803 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3804 /* line-out */
3805 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3806 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3807 /* Line-in */
3808 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3809 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3810 /* CD */
3811 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3812 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3813 /* Mic1 (rear panel) */
3814 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3815 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3816 /* Mic2 (front panel) */
3817 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3818 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3819 /* headphone */
3820 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3821 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3822 /* change to EAPD mode */
3823 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3824 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3825
3826 { }
3827};
3828
Takashi Iwaia9111322011-05-02 11:30:18 +02003829static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003830 /* change to EAPD mode */
3831 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3832 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3833
Kailang Yangdf694da2005-12-05 19:42:22 +01003834 /* Headphone output */
3835 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3836 /* Front output*/
3837 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3838 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3839
3840 /* Line In pin widget for input */
3841 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3842 /* CD pin widget for input */
3843 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3844 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3845 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3846
3847 /* change to EAPD mode */
3848 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3849 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3850
3851 { }
3852};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003853
3854/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003855 * LG m1 express dual
3856 *
3857 * Pin assignment:
3858 * Rear Line-In/Out (blue): 0x14
3859 * Build-in Mic-In: 0x15
3860 * Speaker-out: 0x17
3861 * HP-Out (green): 0x1b
3862 * Mic-In/Out (red): 0x19
3863 * SPDIF-Out: 0x1e
3864 */
3865
3866/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003867static const hda_nid_t alc880_lg_dac_nids[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003868 0x05, 0x02, 0x03
3869};
3870
3871/* seems analog CD is not working */
Takashi Iwaia9111322011-05-02 11:30:18 +02003872static const struct hda_input_mux alc880_lg_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003873 .num_items = 3,
3874 .items = {
3875 { "Mic", 0x1 },
3876 { "Line", 0x5 },
3877 { "Internal Mic", 0x6 },
3878 },
3879};
3880
3881/* 2,4,6 channel modes */
Takashi Iwaia9111322011-05-02 11:30:18 +02003882static const struct hda_verb alc880_lg_ch2_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003883 /* set line-in and mic-in to input */
3884 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3885 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3886 { }
3887};
3888
Takashi Iwaia9111322011-05-02 11:30:18 +02003889static const struct hda_verb alc880_lg_ch4_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003890 /* set line-in to out and mic-in to input */
3891 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3892 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3893 { }
3894};
3895
Takashi Iwaia9111322011-05-02 11:30:18 +02003896static const struct hda_verb alc880_lg_ch6_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003897 /* set line-in and mic-in to output */
3898 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3899 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3900 { }
3901};
3902
Takashi Iwaia9111322011-05-02 11:30:18 +02003903static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003904 { 2, alc880_lg_ch2_init },
3905 { 4, alc880_lg_ch4_init },
3906 { 6, alc880_lg_ch6_init },
3907};
3908
Takashi Iwaia9111322011-05-02 11:30:18 +02003909static const struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003910 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3911 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003912 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3913 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3914 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3915 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3916 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3917 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3918 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3919 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3920 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3921 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3922 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3923 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3924 {
3925 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3926 .name = "Channel Mode",
3927 .info = alc_ch_mode_info,
3928 .get = alc_ch_mode_get,
3929 .put = alc_ch_mode_put,
3930 },
3931 { } /* end */
3932};
3933
Takashi Iwaia9111322011-05-02 11:30:18 +02003934static const struct hda_verb alc880_lg_init_verbs[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003935 /* set capture source to mic-in */
3936 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3937 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3938 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3939 /* mute all amp mixer inputs */
3940 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003941 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3942 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003943 /* line-in to input */
3944 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3945 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3946 /* built-in mic */
3947 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3948 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3949 /* speaker-out */
3950 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3951 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3952 /* mic-in to input */
3953 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3954 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3955 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3956 /* HP-out */
3957 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3958 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3959 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3960 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003961 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003962 { }
3963};
3964
3965/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003966static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003967{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003968 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003969
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003970 spec->autocfg.hp_pins[0] = 0x1b;
3971 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02003972 spec->automute = 1;
3973 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003974}
3975
3976/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003977 * LG LW20
3978 *
3979 * Pin assignment:
3980 * Speaker-out: 0x14
3981 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003982 * Built-in Mic-In: 0x19
3983 * Line-In: 0x1b
3984 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003985 * SPDIF-Out: 0x1e
3986 */
3987
Takashi Iwaia9111322011-05-02 11:30:18 +02003988static const struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003989 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003990 .items = {
3991 { "Mic", 0x0 },
3992 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003993 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003994 },
3995};
3996
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003997#define alc880_lg_lw_modes alc880_threestack_modes
3998
Takashi Iwaia9111322011-05-02 11:30:18 +02003999static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004000 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4001 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4002 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
4003 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
4004 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
4005 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
4006 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
4007 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
4008 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4009 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01004010 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4011 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4012 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
4013 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004014 {
4015 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4016 .name = "Channel Mode",
4017 .info = alc_ch_mode_info,
4018 .get = alc_ch_mode_get,
4019 .put = alc_ch_mode_put,
4020 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004021 { } /* end */
4022};
4023
Takashi Iwaia9111322011-05-02 11:30:18 +02004024static const struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004025 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4026 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
4027 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
4028
Takashi Iwaid6815182006-03-23 16:06:23 +01004029 /* set capture source to mic-in */
4030 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4031 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4032 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02004033 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01004034 /* speaker-out */
4035 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4036 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4037 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01004038 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4039 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4040 /* mic-in to input */
4041 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4042 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4043 /* built-in mic */
4044 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4045 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4046 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004047 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01004048 { }
4049};
4050
4051/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004052static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01004053{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004054 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01004055
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004056 spec->autocfg.hp_pins[0] = 0x1b;
4057 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02004058 spec->automute = 1;
4059 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaid6815182006-03-23 16:06:23 +01004060}
4061
Takashi Iwaia9111322011-05-02 11:30:18 +02004062static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004063 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4064 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
4065 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4066 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4067 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
4068 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
4069 { } /* end */
4070};
4071
Takashi Iwaia9111322011-05-02 11:30:18 +02004072static const struct hda_input_mux alc880_medion_rim_capture_source = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004073 .num_items = 2,
4074 .items = {
4075 { "Mic", 0x0 },
4076 { "Internal Mic", 0x1 },
4077 },
4078};
4079
Takashi Iwaia9111322011-05-02 11:30:18 +02004080static const struct hda_verb alc880_medion_rim_init_verbs[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004081 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4082
4083 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4084 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4085
4086 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4087 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4088 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4089 /* Mic2 (as headphone out) for HP output */
4090 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4091 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4092 /* Internal Speaker */
4093 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4094 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4095
4096 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
4097 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
4098
4099 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4100 { }
4101};
4102
4103/* toggle speaker-output according to the hp-jack state */
4104static void alc880_medion_rim_automute(struct hda_codec *codec)
4105{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004106 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02004107 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004108 /* toggle EAPD */
4109 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004110 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
4111 else
4112 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
4113}
4114
4115static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
4116 unsigned int res)
4117{
4118 /* Looks like the unsol event is incompatible with the standard
4119 * definition. 4bit tag is placed at 28 bit!
4120 */
4121 if ((res >> 28) == ALC880_HP_EVENT)
4122 alc880_medion_rim_automute(codec);
4123}
4124
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004125static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004126{
4127 struct alc_spec *spec = codec->spec;
4128
4129 spec->autocfg.hp_pins[0] = 0x14;
4130 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02004131 spec->automute = 1;
4132 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004133}
4134
Takashi Iwaicb53c622007-08-10 17:21:45 +02004135#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02004136static const struct hda_amp_list alc880_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004137 { 0x0b, HDA_INPUT, 0 },
4138 { 0x0b, HDA_INPUT, 1 },
4139 { 0x0b, HDA_INPUT, 2 },
4140 { 0x0b, HDA_INPUT, 3 },
4141 { 0x0b, HDA_INPUT, 4 },
4142 { } /* end */
4143};
4144
Takashi Iwaia9111322011-05-02 11:30:18 +02004145static const struct hda_amp_list alc880_lg_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004146 { 0x0b, HDA_INPUT, 1 },
4147 { 0x0b, HDA_INPUT, 6 },
4148 { 0x0b, HDA_INPUT, 7 },
4149 { } /* end */
4150};
4151#endif
4152
Takashi Iwaid6815182006-03-23 16:06:23 +01004153/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004154 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004155 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004156
Takashi Iwai584c0c42011-03-10 12:51:11 +01004157static void alc_init_special_input_src(struct hda_codec *codec);
4158
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159static int alc_init(struct hda_codec *codec)
4160{
4161 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004162 unsigned int i;
4163
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004164 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004165 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004166
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004167 for (i = 0; i < spec->num_init_verbs; i++)
4168 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01004169 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004170
4171 if (spec->init_hook)
4172 spec->init_hook(codec);
4173
Takashi Iwai58701122011-01-13 15:41:45 +01004174 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
4175
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004176 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 return 0;
4178}
4179
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004180static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
4181{
4182 struct alc_spec *spec = codec->spec;
4183
4184 if (spec->unsol_event)
4185 spec->unsol_event(codec, res);
4186}
4187
Takashi Iwaicb53c622007-08-10 17:21:45 +02004188#ifdef CONFIG_SND_HDA_POWER_SAVE
4189static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
4190{
4191 struct alc_spec *spec = codec->spec;
4192 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
4193}
4194#endif
4195
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196/*
4197 * Analog playback callbacks
4198 */
4199static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
4200 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004201 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202{
4203 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01004204 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
4205 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206}
4207
4208static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4209 struct hda_codec *codec,
4210 unsigned int stream_tag,
4211 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004212 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213{
4214 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004215 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
4216 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217}
4218
4219static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4220 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004221 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223 struct alc_spec *spec = codec->spec;
4224 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
4225}
4226
4227/*
4228 * Digital out
4229 */
4230static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
4231 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004232 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233{
4234 struct alc_spec *spec = codec->spec;
4235 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4236}
4237
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004238static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4239 struct hda_codec *codec,
4240 unsigned int stream_tag,
4241 unsigned int format,
4242 struct snd_pcm_substream *substream)
4243{
4244 struct alc_spec *spec = codec->spec;
4245 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4246 stream_tag, format, substream);
4247}
4248
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004249static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4250 struct hda_codec *codec,
4251 struct snd_pcm_substream *substream)
4252{
4253 struct alc_spec *spec = codec->spec;
4254 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4255}
4256
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
4258 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004259 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260{
4261 struct alc_spec *spec = codec->spec;
4262 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4263}
4264
4265/*
4266 * Analog capture
4267 */
Takashi Iwai63300792008-01-24 15:31:36 +01004268static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 struct hda_codec *codec,
4270 unsigned int stream_tag,
4271 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004272 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273{
4274 struct alc_spec *spec = codec->spec;
4275
Takashi Iwai63300792008-01-24 15:31:36 +01004276 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 stream_tag, 0, format);
4278 return 0;
4279}
4280
Takashi Iwai63300792008-01-24 15:31:36 +01004281static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004283 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284{
4285 struct alc_spec *spec = codec->spec;
4286
Takashi Iwai888afa12008-03-18 09:57:50 +01004287 snd_hda_codec_cleanup_stream(codec,
4288 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 return 0;
4290}
4291
Takashi Iwai840b64c2010-07-13 22:49:01 +02004292/* analog capture with dynamic dual-adc changes */
4293static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4294 struct hda_codec *codec,
4295 unsigned int stream_tag,
4296 unsigned int format,
4297 struct snd_pcm_substream *substream)
4298{
4299 struct alc_spec *spec = codec->spec;
4300 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
4301 spec->cur_adc_stream_tag = stream_tag;
4302 spec->cur_adc_format = format;
4303 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4304 return 0;
4305}
4306
4307static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4308 struct hda_codec *codec,
4309 struct snd_pcm_substream *substream)
4310{
4311 struct alc_spec *spec = codec->spec;
4312 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4313 spec->cur_adc = 0;
4314 return 0;
4315}
4316
Takashi Iwaia9111322011-05-02 11:30:18 +02004317static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02004318 .substreams = 1,
4319 .channels_min = 2,
4320 .channels_max = 2,
4321 .nid = 0, /* fill later */
4322 .ops = {
4323 .prepare = dualmic_capture_pcm_prepare,
4324 .cleanup = dualmic_capture_pcm_cleanup
4325 },
4326};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
4328/*
4329 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004330static const struct hda_pcm_stream alc880_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 .substreams = 1,
4332 .channels_min = 2,
4333 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004334 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 .ops = {
4336 .open = alc880_playback_pcm_open,
4337 .prepare = alc880_playback_pcm_prepare,
4338 .cleanup = alc880_playback_pcm_cleanup
4339 },
4340};
4341
Takashi Iwaia9111322011-05-02 11:30:18 +02004342static const struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004343 .substreams = 1,
4344 .channels_min = 2,
4345 .channels_max = 2,
4346 /* NID is set in alc_build_pcms */
4347};
4348
Takashi Iwaia9111322011-05-02 11:30:18 +02004349static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01004350 .substreams = 1,
4351 .channels_min = 2,
4352 .channels_max = 2,
4353 /* NID is set in alc_build_pcms */
4354};
4355
Takashi Iwaia9111322011-05-02 11:30:18 +02004356static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004357 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 .channels_min = 2,
4359 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004360 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01004362 .prepare = alc880_alt_capture_pcm_prepare,
4363 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 },
4365};
4366
Takashi Iwaia9111322011-05-02 11:30:18 +02004367static const struct hda_pcm_stream alc880_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 .substreams = 1,
4369 .channels_min = 2,
4370 .channels_max = 2,
4371 /* NID is set in alc_build_pcms */
4372 .ops = {
4373 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004374 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004375 .prepare = alc880_dig_playback_pcm_prepare,
4376 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 },
4378};
4379
Takashi Iwaia9111322011-05-02 11:30:18 +02004380static const struct hda_pcm_stream alc880_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 .substreams = 1,
4382 .channels_min = 2,
4383 .channels_max = 2,
4384 /* NID is set in alc_build_pcms */
4385};
4386
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004387/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02004388static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004389 .substreams = 0,
4390 .channels_min = 0,
4391 .channels_max = 0,
4392};
4393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394static int alc_build_pcms(struct hda_codec *codec)
4395{
4396 struct alc_spec *spec = codec->spec;
4397 struct hda_pcm *info = spec->pcm_rec;
4398 int i;
4399
4400 codec->num_pcms = 1;
4401 codec->pcm_info = info;
4402
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004403 if (spec->no_analog)
4404 goto skip_analog;
4405
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004406 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4407 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004409
Takashi Iwai4a471b72005-12-07 13:56:29 +01004410 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004411 if (snd_BUG_ON(!spec->multiout.dac_nids))
4412 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004413 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
4414 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4415 }
4416 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004417 if (snd_BUG_ON(!spec->adc_nids))
4418 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004419 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
4420 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
Takashi Iwai4a471b72005-12-07 13:56:29 +01004423 if (spec->channel_mode) {
4424 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4425 for (i = 0; i < spec->num_channel_mode; i++) {
4426 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4427 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 }
4430 }
4431
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004432 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004433 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004435 snprintf(spec->stream_name_digital,
4436 sizeof(spec->stream_name_digital),
4437 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004438 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004439 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004440 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004442 if (spec->dig_out_type)
4443 info->pcm_type = spec->dig_out_type;
4444 else
4445 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004446 if (spec->multiout.dig_out_nid &&
4447 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4449 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4450 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004451 if (spec->dig_in_nid &&
4452 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4454 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4455 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004456 /* FIXME: do we need this for all Realtek codec models? */
4457 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 }
4459
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004460 if (spec->no_analog)
4461 return 0;
4462
Takashi Iwaie08a0072006-09-07 17:52:14 +02004463 /* If the use of more than one ADC is requested for the current
4464 * model, configure a second analog capture-only PCM.
4465 */
4466 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004467 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4468 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004469 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004470 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004471 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004472 if (spec->alt_dac_nid) {
4473 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4474 *spec->stream_analog_alt_playback;
4475 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4476 spec->alt_dac_nid;
4477 } else {
4478 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4479 alc_pcm_null_stream;
4480 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4481 }
Raymond Yauce85c9a2011-05-03 13:33:53 +08004482 if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
Takashi Iwai63300792008-01-24 15:31:36 +01004483 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4484 *spec->stream_analog_alt_capture;
4485 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4486 spec->adc_nids[1];
4487 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4488 spec->num_adc_nids - 1;
4489 } else {
4490 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4491 alc_pcm_null_stream;
4492 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004493 }
4494 }
4495
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 return 0;
4497}
4498
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004499static inline void alc_shutup(struct hda_codec *codec)
4500{
Takashi Iwai1c716152011-04-07 10:37:16 +02004501 struct alc_spec *spec = codec->spec;
4502
4503 if (spec && spec->shutup)
4504 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004505 snd_hda_shutup_pins(codec);
4506}
4507
Takashi Iwai603c4012008-07-30 15:01:44 +02004508static void alc_free_kctls(struct hda_codec *codec)
4509{
4510 struct alc_spec *spec = codec->spec;
4511
4512 if (spec->kctls.list) {
4513 struct snd_kcontrol_new *kctl = spec->kctls.list;
4514 int i;
4515 for (i = 0; i < spec->kctls.used; i++)
4516 kfree(kctl[i].name);
4517 }
4518 snd_array_free(&spec->kctls);
4519}
4520
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521static void alc_free(struct hda_codec *codec)
4522{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004523 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004524
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004525 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004526 return;
4527
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004528 alc_shutup(codec);
Takashi Iwaicd372fb2011-03-03 14:40:14 +01004529 snd_hda_input_jack_free(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004530 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004531 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004532 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533}
4534
Hector Martinf5de24b2009-12-20 22:51:31 +01004535#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004536static void alc_power_eapd(struct hda_codec *codec)
4537{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02004538 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004539}
4540
Hector Martinf5de24b2009-12-20 22:51:31 +01004541static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4542{
4543 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004544 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004545 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004546 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004547 return 0;
4548}
4549#endif
4550
Takashi Iwaie044c392008-10-27 16:56:24 +01004551#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004552static int alc_resume(struct hda_codec *codec)
4553{
Takashi Iwai1c716152011-04-07 10:37:16 +02004554 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01004555 codec->patch_ops.init(codec);
4556 snd_hda_codec_resume_amp(codec);
4557 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004558 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004559 return 0;
4560}
Takashi Iwaie044c392008-10-27 16:56:24 +01004561#endif
4562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563/*
4564 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004565static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 .build_controls = alc_build_controls,
4567 .build_pcms = alc_build_pcms,
4568 .init = alc_init,
4569 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004570 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004571#ifdef SND_HDA_NEEDS_RESUME
4572 .resume = alc_resume,
4573#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004574#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004575 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004576 .check_power_status = alc_check_power_status,
4577#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004578 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579};
4580
Kailang Yangc027ddc2010-03-19 11:33:06 +01004581/* replace the codec chip_name with the given string */
4582static int alc_codec_rename(struct hda_codec *codec, const char *name)
4583{
4584 kfree(codec->chip_name);
4585 codec->chip_name = kstrdup(name, GFP_KERNEL);
4586 if (!codec->chip_name) {
4587 alc_free(codec);
4588 return -ENOMEM;
4589 }
4590 return 0;
4591}
4592
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004593/*
4594 * Test configuration for debugging
4595 *
4596 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4597 * enum controls.
4598 */
4599#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004600static const hda_nid_t alc880_test_dac_nids[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004601 0x02, 0x03, 0x04, 0x05
4602};
4603
Takashi Iwaia9111322011-05-02 11:30:18 +02004604static const struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004605 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004606 .items = {
4607 { "In-1", 0x0 },
4608 { "In-2", 0x1 },
4609 { "In-3", 0x2 },
4610 { "In-4", 0x3 },
4611 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004612 { "Front", 0x5 },
4613 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004614 },
4615};
4616
Takashi Iwaia9111322011-05-02 11:30:18 +02004617static const struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004618 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004619 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004620 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004621 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004622};
4623
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004624static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4625 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004626{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004627 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004628 "N/A", "Line Out", "HP Out",
4629 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4630 };
4631 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4632 uinfo->count = 1;
4633 uinfo->value.enumerated.items = 8;
4634 if (uinfo->value.enumerated.item >= 8)
4635 uinfo->value.enumerated.item = 7;
4636 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4637 return 0;
4638}
4639
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004640static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4641 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004642{
4643 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4644 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4645 unsigned int pin_ctl, item = 0;
4646
4647 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4648 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4649 if (pin_ctl & AC_PINCTL_OUT_EN) {
4650 if (pin_ctl & AC_PINCTL_HP_EN)
4651 item = 2;
4652 else
4653 item = 1;
4654 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4655 switch (pin_ctl & AC_PINCTL_VREFEN) {
4656 case AC_PINCTL_VREF_HIZ: item = 3; break;
4657 case AC_PINCTL_VREF_50: item = 4; break;
4658 case AC_PINCTL_VREF_GRD: item = 5; break;
4659 case AC_PINCTL_VREF_80: item = 6; break;
4660 case AC_PINCTL_VREF_100: item = 7; break;
4661 }
4662 }
4663 ucontrol->value.enumerated.item[0] = item;
4664 return 0;
4665}
4666
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004667static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4668 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004669{
4670 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4671 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004672 static const unsigned int ctls[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004673 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4674 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4675 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4676 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4677 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4678 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4679 };
4680 unsigned int old_ctl, new_ctl;
4681
4682 old_ctl = snd_hda_codec_read(codec, nid, 0,
4683 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4684 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4685 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004686 int val;
4687 snd_hda_codec_write_cache(codec, nid, 0,
4688 AC_VERB_SET_PIN_WIDGET_CONTROL,
4689 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004690 val = ucontrol->value.enumerated.item[0] >= 3 ?
4691 HDA_AMP_MUTE : 0;
4692 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4693 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004694 return 1;
4695 }
4696 return 0;
4697}
4698
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004699static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4700 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004701{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004702 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004703 "Front", "Surround", "CLFE", "Side"
4704 };
4705 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4706 uinfo->count = 1;
4707 uinfo->value.enumerated.items = 4;
4708 if (uinfo->value.enumerated.item >= 4)
4709 uinfo->value.enumerated.item = 3;
4710 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4711 return 0;
4712}
4713
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004714static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4715 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004716{
4717 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4718 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4719 unsigned int sel;
4720
4721 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4722 ucontrol->value.enumerated.item[0] = sel & 3;
4723 return 0;
4724}
4725
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004726static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4727 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004728{
4729 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4730 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4731 unsigned int sel;
4732
4733 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4734 if (ucontrol->value.enumerated.item[0] != sel) {
4735 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004736 snd_hda_codec_write_cache(codec, nid, 0,
4737 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004738 return 1;
4739 }
4740 return 0;
4741}
4742
4743#define PIN_CTL_TEST(xname,nid) { \
4744 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4745 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004746 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004747 .info = alc_test_pin_ctl_info, \
4748 .get = alc_test_pin_ctl_get, \
4749 .put = alc_test_pin_ctl_put, \
4750 .private_value = nid \
4751 }
4752
4753#define PIN_SRC_TEST(xname,nid) { \
4754 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4755 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004756 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004757 .info = alc_test_pin_src_info, \
4758 .get = alc_test_pin_src_get, \
4759 .put = alc_test_pin_src_put, \
4760 .private_value = nid \
4761 }
4762
Takashi Iwaia9111322011-05-02 11:30:18 +02004763static const struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004764 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4765 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4766 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4767 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004768 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4769 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4770 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4771 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004772 PIN_CTL_TEST("Front Pin Mode", 0x14),
4773 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4774 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4775 PIN_CTL_TEST("Side Pin Mode", 0x17),
4776 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4777 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4778 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4779 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4780 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4781 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4782 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4783 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4784 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4785 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4786 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4787 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4788 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4789 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4790 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4791 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4792 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4793 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004794 {
4795 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4796 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004797 .info = alc_ch_mode_info,
4798 .get = alc_ch_mode_get,
4799 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004800 },
4801 { } /* end */
4802};
4803
Takashi Iwaia9111322011-05-02 11:30:18 +02004804static const struct hda_verb alc880_test_init_verbs[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004805 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004806 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4808 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4809 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4810 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4811 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4812 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4813 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004814 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004815 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4816 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4817 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4818 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004819 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004820 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4821 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4822 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4823 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004824 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004825 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4826 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4827 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4828 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004829 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004830 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4831 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004832 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4833 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4834 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004835 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004836 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4837 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4838 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4839 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004840 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004841 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004842 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004843 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004844 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004845 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004846 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004847 /* Analog input/passthru */
4848 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4849 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4850 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4851 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4852 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004853 { }
4854};
4855#endif
4856
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857/*
4858 */
4859
Takashi Iwaiea734962011-01-17 11:29:34 +01004860static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004861 [ALC880_3ST] = "3stack",
4862 [ALC880_TCL_S700] = "tcl",
4863 [ALC880_3ST_DIG] = "3stack-digout",
4864 [ALC880_CLEVO] = "clevo",
4865 [ALC880_5ST] = "5stack",
4866 [ALC880_5ST_DIG] = "5stack-digout",
4867 [ALC880_W810] = "w810",
4868 [ALC880_Z71V] = "z71v",
4869 [ALC880_6ST] = "6stack",
4870 [ALC880_6ST_DIG] = "6stack-digout",
4871 [ALC880_ASUS] = "asus",
4872 [ALC880_ASUS_W1V] = "asus-w1v",
4873 [ALC880_ASUS_DIG] = "asus-dig",
4874 [ALC880_ASUS_DIG2] = "asus-dig2",
4875 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004876 [ALC880_UNIWILL_P53] = "uniwill-p53",
4877 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004878 [ALC880_F1734] = "F1734",
4879 [ALC880_LG] = "lg",
4880 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004881 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004882#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004883 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004884#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004885 [ALC880_AUTO] = "auto",
4886};
4887
Takashi Iwaia9111322011-05-02 11:30:18 +02004888static const struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004889 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004890 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4891 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4892 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4893 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4894 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4895 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4896 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4897 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004898 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004899 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4900 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4901 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4902 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4903 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4904 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4905 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4906 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4907 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4908 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004909 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004910 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4911 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4912 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004913 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004914 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004915 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4916 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004917 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4918 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004919 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4920 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4921 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4922 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004923 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4924 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004925 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004926 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004927 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Justin P. Mattocka2e2bc22011-02-24 22:16:02 -08004928 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004929 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4930 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004931 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004932 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004933 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004934 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004935 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004936 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004937 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004938 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004939 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004940 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004941 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004942 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004943 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004944 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4945 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4946 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4947 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004948 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4949 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004950 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004951 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004952 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4953 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004954 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4955 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4956 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004957 /* default Intel */
4958 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004959 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4960 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 {}
4962};
4963
Takashi Iwai16ded522005-06-10 19:58:24 +02004964/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004965 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004966 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004967static const struct alc_config_preset alc880_presets[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02004968 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004969 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004970 .init_verbs = { alc880_volume_init_verbs,
4971 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004972 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004973 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004974 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4975 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004976 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004977 .input_mux = &alc880_capture_source,
4978 },
4979 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004980 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004981 .init_verbs = { alc880_volume_init_verbs,
4982 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004983 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004984 .dac_nids = alc880_dac_nids,
4985 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004986 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4987 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004988 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004989 .input_mux = &alc880_capture_source,
4990 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004991 [ALC880_TCL_S700] = {
4992 .mixers = { alc880_tcl_s700_mixer },
4993 .init_verbs = { alc880_volume_init_verbs,
4994 alc880_pin_tcl_S700_init_verbs,
4995 alc880_gpio2_init_verbs },
4996 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4997 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004998 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4999 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01005000 .hp_nid = 0x03,
5001 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5002 .channel_mode = alc880_2_jack_modes,
5003 .input_mux = &alc880_capture_source,
5004 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005005 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005006 .mixers = { alc880_three_stack_mixer,
5007 alc880_five_stack_mixer},
5008 .init_verbs = { alc880_volume_init_verbs,
5009 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005010 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5011 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005012 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5013 .channel_mode = alc880_fivestack_modes,
5014 .input_mux = &alc880_capture_source,
5015 },
5016 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005017 .mixers = { alc880_three_stack_mixer,
5018 alc880_five_stack_mixer },
5019 .init_verbs = { alc880_volume_init_verbs,
5020 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005021 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5022 .dac_nids = alc880_dac_nids,
5023 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005024 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5025 .channel_mode = alc880_fivestack_modes,
5026 .input_mux = &alc880_capture_source,
5027 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005028 [ALC880_6ST] = {
5029 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005030 .init_verbs = { alc880_volume_init_verbs,
5031 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005032 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5033 .dac_nids = alc880_6st_dac_nids,
5034 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5035 .channel_mode = alc880_sixstack_modes,
5036 .input_mux = &alc880_6stack_capture_source,
5037 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005038 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005039 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005040 .init_verbs = { alc880_volume_init_verbs,
5041 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005042 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5043 .dac_nids = alc880_6st_dac_nids,
5044 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005045 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5046 .channel_mode = alc880_sixstack_modes,
5047 .input_mux = &alc880_6stack_capture_source,
5048 },
5049 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005050 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005051 .init_verbs = { alc880_volume_init_verbs,
5052 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005053 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005054 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
5055 .dac_nids = alc880_w810_dac_nids,
5056 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005057 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
5058 .channel_mode = alc880_w810_modes,
5059 .input_mux = &alc880_capture_source,
5060 },
5061 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005062 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005063 .init_verbs = { alc880_volume_init_verbs,
5064 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005065 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
5066 .dac_nids = alc880_z71v_dac_nids,
5067 .dig_out_nid = ALC880_DIGOUT_NID,
5068 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005069 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5070 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02005071 .input_mux = &alc880_capture_source,
5072 },
5073 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005074 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005075 .init_verbs = { alc880_volume_init_verbs,
5076 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005077 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
5078 .dac_nids = alc880_f1734_dac_nids,
5079 .hp_nid = 0x02,
5080 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5081 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01005082 .input_mux = &alc880_f1734_capture_source,
5083 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005084 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005085 .init_hook = alc_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02005086 },
5087 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005088 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005089 .init_verbs = { alc880_volume_init_verbs,
5090 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005091 alc880_gpio1_init_verbs },
5092 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5093 .dac_nids = alc880_asus_dac_nids,
5094 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5095 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005096 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005097 .input_mux = &alc880_capture_source,
5098 },
5099 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005100 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005101 .init_verbs = { alc880_volume_init_verbs,
5102 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005103 alc880_gpio1_init_verbs },
5104 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5105 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005106 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005107 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5108 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005109 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005110 .input_mux = &alc880_capture_source,
5111 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005112 [ALC880_ASUS_DIG2] = {
5113 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005114 .init_verbs = { alc880_volume_init_verbs,
5115 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01005116 alc880_gpio2_init_verbs }, /* use GPIO2 */
5117 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5118 .dac_nids = alc880_asus_dac_nids,
5119 .dig_out_nid = ALC880_DIGOUT_NID,
5120 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5121 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005122 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005123 .input_mux = &alc880_capture_source,
5124 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005125 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005126 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005127 .init_verbs = { alc880_volume_init_verbs,
5128 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005129 alc880_gpio1_init_verbs },
5130 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5131 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005132 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005133 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5134 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005135 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005136 .input_mux = &alc880_capture_source,
5137 },
5138 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005139 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02005140 .init_verbs = { alc880_volume_init_verbs,
5141 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005142 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5143 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005144 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005145 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5146 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005147 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005148 .input_mux = &alc880_capture_source,
5149 },
Kailang Yangccc656c2006-10-17 12:32:26 +02005150 [ALC880_UNIWILL] = {
5151 .mixers = { alc880_uniwill_mixer },
5152 .init_verbs = { alc880_volume_init_verbs,
5153 alc880_uniwill_init_verbs },
5154 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5155 .dac_nids = alc880_asus_dac_nids,
5156 .dig_out_nid = ALC880_DIGOUT_NID,
5157 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5158 .channel_mode = alc880_threestack_modes,
5159 .need_dac_fix = 1,
5160 .input_mux = &alc880_capture_source,
5161 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005162 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02005163 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02005164 },
5165 [ALC880_UNIWILL_P53] = {
5166 .mixers = { alc880_uniwill_p53_mixer },
5167 .init_verbs = { alc880_volume_init_verbs,
5168 alc880_uniwill_p53_init_verbs },
5169 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5170 .dac_nids = alc880_asus_dac_nids,
5171 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005172 .channel_mode = alc880_threestack_modes,
5173 .input_mux = &alc880_capture_source,
5174 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005175 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005176 .init_hook = alc_hp_automute,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005177 },
5178 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005179 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005180 .init_verbs = { alc880_volume_init_verbs,
5181 alc880_uniwill_p53_init_verbs,
5182 alc880_beep_init_verbs },
5183 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5184 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02005185 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005186 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5187 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02005188 .input_mux = &alc880_capture_source,
5189 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005190 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005191 .init_hook = alc_hp_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02005192 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005193 [ALC880_CLEVO] = {
5194 .mixers = { alc880_three_stack_mixer },
5195 .init_verbs = { alc880_volume_init_verbs,
5196 alc880_pin_clevo_init_verbs },
5197 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5198 .dac_nids = alc880_dac_nids,
5199 .hp_nid = 0x03,
5200 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5201 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005202 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005203 .input_mux = &alc880_capture_source,
5204 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005205 [ALC880_LG] = {
5206 .mixers = { alc880_lg_mixer },
5207 .init_verbs = { alc880_volume_init_verbs,
5208 alc880_lg_init_verbs },
5209 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
5210 .dac_nids = alc880_lg_dac_nids,
5211 .dig_out_nid = ALC880_DIGOUT_NID,
5212 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
5213 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005214 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005215 .input_mux = &alc880_lg_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005216 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005217 .setup = alc880_lg_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005218 .init_hook = alc_hp_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005219#ifdef CONFIG_SND_HDA_POWER_SAVE
5220 .loopbacks = alc880_lg_loopbacks,
5221#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005222 },
Takashi Iwaid6815182006-03-23 16:06:23 +01005223 [ALC880_LG_LW] = {
5224 .mixers = { alc880_lg_lw_mixer },
5225 .init_verbs = { alc880_volume_init_verbs,
5226 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005227 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01005228 .dac_nids = alc880_dac_nids,
5229 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005230 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
5231 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01005232 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005233 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005234 .setup = alc880_lg_lw_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005235 .init_hook = alc_hp_automute,
Takashi Iwaid6815182006-03-23 16:06:23 +01005236 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005237 [ALC880_MEDION_RIM] = {
5238 .mixers = { alc880_medion_rim_mixer },
5239 .init_verbs = { alc880_volume_init_verbs,
5240 alc880_medion_rim_init_verbs,
5241 alc_gpio2_init_verbs },
5242 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5243 .dac_nids = alc880_dac_nids,
5244 .dig_out_nid = ALC880_DIGOUT_NID,
5245 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5246 .channel_mode = alc880_2_jack_modes,
5247 .input_mux = &alc880_medion_rim_capture_source,
5248 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005249 .setup = alc880_medion_rim_setup,
5250 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005251 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005252#ifdef CONFIG_SND_DEBUG
5253 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005254 .mixers = { alc880_test_mixer },
5255 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005256 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5257 .dac_nids = alc880_test_dac_nids,
5258 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005259 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5260 .channel_mode = alc880_test_modes,
5261 .input_mux = &alc880_test_capture_source,
5262 },
5263#endif
5264};
5265
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005266/*
5267 * Automatic parse of I/O pins from the BIOS configuration
5268 */
5269
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005270enum {
5271 ALC_CTL_WIDGET_VOL,
5272 ALC_CTL_WIDGET_MUTE,
5273 ALC_CTL_BIND_MUTE,
5274};
Takashi Iwaia9111322011-05-02 11:30:18 +02005275static const struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005276 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5277 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005278 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005279};
5280
Takashi Iwaice764ab2011-04-27 16:35:23 +02005281static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
5282{
5283 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
5284 return snd_array_new(&spec->kctls);
5285}
5286
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005287/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005288static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005289 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005290{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005291 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005292
Takashi Iwaice764ab2011-04-27 16:35:23 +02005293 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02005294 if (!knew)
5295 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005296 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005297 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005298 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005299 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005300 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005301 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005302 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005303 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005304 return 0;
5305}
5306
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005307static int add_control_with_pfx(struct alc_spec *spec, int type,
5308 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005309 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005310{
5311 char name[32];
5312 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005313 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005314}
5315
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005316#define add_pb_vol_ctrl(spec, type, pfx, val) \
5317 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5318#define add_pb_sw_ctrl(spec, type, pfx, val) \
5319 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5320#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5321 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5322#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5323 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005324
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005325#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5326#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5327#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5328#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005329#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5330#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5331#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5332#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5333#define ALC880_PIN_CD_NID 0x1c
5334
5335/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005336static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
5337 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005338{
5339 hda_nid_t nid;
5340 int assigned[4];
5341 int i, j;
5342
5343 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005344 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005345
5346 /* check the pins hardwired to audio widget */
5347 for (i = 0; i < cfg->line_outs; i++) {
5348 nid = cfg->line_out_pins[i];
5349 if (alc880_is_fixed_pin(nid)) {
5350 int idx = alc880_fixed_pin_idx(nid);
Takashi Iwaidda14412011-05-02 11:29:30 +02005351 spec->private_dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005352 assigned[idx] = 1;
5353 }
5354 }
5355 /* left pins can be connect to any audio widget */
5356 for (i = 0; i < cfg->line_outs; i++) {
5357 nid = cfg->line_out_pins[i];
5358 if (alc880_is_fixed_pin(nid))
5359 continue;
5360 /* search for an empty channel */
5361 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005362 if (!assigned[j]) {
Takashi Iwaidda14412011-05-02 11:29:30 +02005363 spec->private_dac_nids[i] =
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005364 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005365 assigned[j] = 1;
5366 break;
5367 }
5368 }
5369 }
5370 spec->multiout.num_dacs = cfg->line_outs;
5371 return 0;
5372}
5373
Takashi Iwaice764ab2011-04-27 16:35:23 +02005374static const char *alc_get_line_out_pfx(struct alc_spec *spec,
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005375 bool can_be_master)
5376{
Takashi Iwaice764ab2011-04-27 16:35:23 +02005377 struct auto_pin_cfg *cfg = &spec->autocfg;
5378
5379 if (cfg->line_outs == 1 && !spec->multi_ios &&
5380 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005381 return "Master";
5382
5383 switch (cfg->line_out_type) {
5384 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01005385 if (cfg->line_outs == 1)
5386 return "Speaker";
5387 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005388 case AUTO_PIN_HP_OUT:
5389 return "Headphone";
5390 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02005391 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005392 return "PCM";
5393 break;
5394 }
5395 return NULL;
5396}
5397
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005398/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01005399static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
5400 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005401{
Takashi Iwaiea734962011-01-17 11:29:34 +01005402 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005403 "Front", "Surround", NULL /*CLFE*/, "Side"
5404 };
Takashi Iwaice764ab2011-04-27 16:35:23 +02005405 const char *pfx = alc_get_line_out_pfx(spec, false);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005406 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005407 int i, err, noutputs;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005408
Takashi Iwaice764ab2011-04-27 16:35:23 +02005409 noutputs = cfg->line_outs;
5410 if (spec->multi_ios > 0)
5411 noutputs += spec->multi_ios;
5412
5413 for (i = 0; i < noutputs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005414 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005415 continue;
5416 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005417 if (!pfx && i == 2) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005418 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005419 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5420 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005421 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
5422 HDA_OUTPUT));
5423 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005424 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005425 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5426 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005427 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
5428 HDA_OUTPUT));
5429 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005430 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005431 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5432 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005433 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
5434 HDA_INPUT));
5435 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005436 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005437 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5438 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005439 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
5440 HDA_INPUT));
5441 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005442 return err;
5443 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005444 const char *name = pfx;
David Henningsson7e59e092011-03-04 14:22:25 +01005445 int index = i;
5446 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005447 name = chname[i];
David Henningsson7e59e092011-03-04 14:22:25 +01005448 index = 0;
5449 }
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005450 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson7e59e092011-03-04 14:22:25 +01005451 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005452 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
5453 HDA_OUTPUT));
5454 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005455 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005456 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson7e59e092011-03-04 14:22:25 +01005457 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005458 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
5459 HDA_INPUT));
5460 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005461 return err;
5462 }
5463 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005464 return 0;
5465}
5466
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005467/* add playback controls for speaker and HP outputs */
5468static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5469 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005470{
5471 hda_nid_t nid;
5472 int err;
5473
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005474 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005475 return 0;
5476
5477 if (alc880_is_fixed_pin(pin)) {
5478 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005479 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005480 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005481 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005482 else
5483 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005484 /* control HP volume/switch on the output mixer amp */
5485 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005486 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005487 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5488 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005489 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005490 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005491 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5492 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005493 return err;
5494 } else if (alc880_is_multi_pin(pin)) {
5495 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005496 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005497 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005498 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5499 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005500 return err;
5501 }
5502 return 0;
5503}
5504
5505/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005506static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005507 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005508 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005509{
Kailang Yangdf694da2005-12-05 19:42:22 +01005510 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005511
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005512 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005513 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5514 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005515 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005516 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005517 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5518 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005519 return err;
5520 return 0;
5521}
5522
Takashi Iwai05f5f472009-08-25 13:10:18 +02005523static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005524{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005525 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5526 return (pincap & AC_PINCAP_IN) != 0;
5527}
5528
5529/* create playback/capture controls for input pins */
5530static int alc_auto_create_input_ctls(struct hda_codec *codec,
5531 const struct auto_pin_cfg *cfg,
5532 hda_nid_t mixer,
5533 hda_nid_t cap1, hda_nid_t cap2)
5534{
5535 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005536 struct hda_input_mux *imux = &spec->private_imux[0];
David Henningsson5322bf22011-01-05 11:03:56 +01005537 int i, err, idx, type_idx = 0;
5538 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005539
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005540 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005541 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005542 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005543
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005544 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005545 if (!alc_is_input_pin(codec, pin))
5546 continue;
5547
David Henningsson5322bf22011-01-05 11:03:56 +01005548 label = hda_get_autocfg_input_label(codec, cfg, i);
5549 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005550 type_idx++;
5551 else
5552 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005553 prev_label = label;
5554
Takashi Iwai05f5f472009-08-25 13:10:18 +02005555 if (mixer) {
5556 idx = get_connection_index(codec, mixer, pin);
5557 if (idx >= 0) {
5558 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005559 label, type_idx,
5560 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005561 if (err < 0)
5562 return err;
5563 }
5564 }
5565
5566 if (!cap1)
5567 continue;
5568 idx = get_connection_index(codec, cap1, pin);
5569 if (idx < 0 && cap2)
5570 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005571 if (idx >= 0)
5572 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005573 }
5574 return 0;
5575}
5576
Takashi Iwai05f5f472009-08-25 13:10:18 +02005577static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5578 const struct auto_pin_cfg *cfg)
5579{
5580 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5581}
5582
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005583static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5584 unsigned int pin_type)
5585{
5586 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5587 pin_type);
5588 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005589 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5590 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005591}
5592
Kailang Yangdf694da2005-12-05 19:42:22 +01005593static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5594 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005595 int dac_idx)
5596{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005597 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005598 /* need the manual connection? */
5599 if (alc880_is_multi_pin(nid)) {
5600 struct alc_spec *spec = codec->spec;
5601 int idx = alc880_multi_pin_idx(nid);
5602 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5603 AC_VERB_SET_CONNECT_SEL,
5604 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5605 }
5606}
5607
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005608static int get_pin_type(int line_out_type)
5609{
5610 if (line_out_type == AUTO_PIN_HP_OUT)
5611 return PIN_HP;
5612 else
5613 return PIN_OUT;
5614}
5615
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005616static void alc880_auto_init_multi_out(struct hda_codec *codec)
5617{
5618 struct alc_spec *spec = codec->spec;
5619 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005620
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005621 for (i = 0; i < spec->autocfg.line_outs; i++) {
5622 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005623 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5624 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005625 }
5626}
5627
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005628static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005629{
5630 struct alc_spec *spec = codec->spec;
5631 hda_nid_t pin;
5632
Takashi Iwai82bc9552006-03-21 11:24:42 +01005633 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005634 if (pin) /* connect to front */
5635 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005636 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005637 if (pin) /* connect to front */
5638 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5639}
5640
5641static void alc880_auto_init_analog_input(struct hda_codec *codec)
5642{
5643 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005644 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005645 int i;
5646
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005647 for (i = 0; i < cfg->num_inputs; i++) {
5648 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005649 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005650 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005651 if (nid != ALC880_PIN_CD_NID &&
5652 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005653 snd_hda_codec_write(codec, nid, 0,
5654 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005655 AMP_OUT_MUTE);
5656 }
5657 }
5658}
5659
Takashi Iwai7f311a42010-04-09 17:32:23 +02005660static void alc880_auto_init_input_src(struct hda_codec *codec)
5661{
5662 struct alc_spec *spec = codec->spec;
5663 int c;
5664
5665 for (c = 0; c < spec->num_adc_nids; c++) {
5666 unsigned int mux_idx;
5667 const struct hda_input_mux *imux;
5668 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5669 imux = &spec->input_mux[mux_idx];
5670 if (!imux->num_items && mux_idx > 0)
5671 imux = &spec->input_mux[0];
5672 if (imux)
5673 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5674 AC_VERB_SET_CONNECT_SEL,
5675 imux->items[0].index);
5676 }
5677}
5678
Takashi Iwaice764ab2011-04-27 16:35:23 +02005679static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
5680
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005681/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005682/* return 1 if successful, 0 if the proper config is not found,
5683 * or a negative error code
5684 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005685static int alc880_parse_auto_config(struct hda_codec *codec)
5686{
5687 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005688 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005689 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005690
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005691 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5692 alc880_ignore);
5693 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005694 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005695 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005696 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005697
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005698 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5699 if (err < 0)
5700 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005701 err = alc_auto_add_multi_channel_mode(codec);
5702 if (err < 0)
5703 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005704 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5705 if (err < 0)
5706 return err;
5707 err = alc880_auto_create_extra_out(spec,
5708 spec->autocfg.speaker_pins[0],
5709 "Speaker");
5710 if (err < 0)
5711 return err;
5712 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5713 "Headphone");
5714 if (err < 0)
5715 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005716 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005717 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005718 return err;
5719
5720 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5721
Takashi Iwai757899a2010-07-30 10:48:14 +02005722 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005723
Takashi Iwai603c4012008-07-30 15:01:44 +02005724 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005725 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005726
Takashi Iwaid88897e2008-10-31 15:01:37 +01005727 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005728
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005729 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005730 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005731
Kailang Yang6227cdc2010-02-25 08:36:52 +01005732 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005733
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005734 return 1;
5735}
5736
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005737/* additional initialization for auto-configuration model */
5738static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005739{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005740 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005741 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005742 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005743 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005744 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005745 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005746 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005747 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005748}
5749
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005750/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5751 * one of two digital mic pins, e.g. on ALC272
5752 */
5753static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005754{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005755 struct alc_spec *spec = codec->spec;
5756 int i;
5757
5758 for (i = 0; i < spec->num_adc_nids; i++) {
5759 hda_nid_t cap = spec->capsrc_nids ?
5760 spec->capsrc_nids[i] : spec->adc_nids[i];
5761 int iidx, eidx;
5762
5763 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5764 if (iidx < 0)
5765 continue;
5766 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5767 if (eidx < 0)
5768 continue;
5769 spec->int_mic.mux_idx = iidx;
5770 spec->ext_mic.mux_idx = eidx;
5771 if (spec->capsrc_nids)
5772 spec->capsrc_nids += i;
5773 spec->adc_nids += i;
5774 spec->num_adc_nids = 1;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005775 /* optional dock-mic */
5776 eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
5777 if (eidx < 0)
5778 spec->dock_mic.pin = 0;
5779 else
5780 spec->dock_mic.mux_idx = eidx;
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005781 return;
5782 }
5783 snd_printd(KERN_INFO "hda_codec: %s: "
5784 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5785 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5786 spec->auto_mic = 0; /* disable auto-mic to be sure */
5787}
5788
Takashi Iwai748cce42010-08-04 07:37:39 +02005789/* select or unmute the given capsrc route */
5790static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5791 int idx)
5792{
5793 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5794 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5795 HDA_AMP_MUTE, 0);
5796 } else {
5797 snd_hda_codec_write_cache(codec, cap, 0,
5798 AC_VERB_SET_CONNECT_SEL, idx);
5799 }
5800}
5801
Takashi Iwai840b64c2010-07-13 22:49:01 +02005802/* set the default connection to that pin */
5803static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5804{
5805 struct alc_spec *spec = codec->spec;
5806 int i;
5807
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005808 if (!pin)
5809 return 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005810 for (i = 0; i < spec->num_adc_nids; i++) {
5811 hda_nid_t cap = spec->capsrc_nids ?
5812 spec->capsrc_nids[i] : spec->adc_nids[i];
5813 int idx;
5814
5815 idx = get_connection_index(codec, cap, pin);
5816 if (idx < 0)
5817 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005818 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005819 return i; /* return the found index */
5820 }
5821 return -1; /* not found */
5822}
5823
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005824/* choose the ADC/MUX containing the input pin and initialize the setup */
5825static void fixup_single_adc(struct hda_codec *codec)
5826{
5827 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005828 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005829 int i;
5830
5831 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005832 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005833 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005834 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005835 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005836 /* use only this ADC */
5837 if (spec->capsrc_nids)
5838 spec->capsrc_nids += i;
5839 spec->adc_nids += i;
5840 spec->num_adc_nids = 1;
Takashi Iwai584c0c42011-03-10 12:51:11 +01005841 spec->single_input_src = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005842 }
5843}
5844
Takashi Iwai840b64c2010-07-13 22:49:01 +02005845/* initialize dual adcs */
5846static void fixup_dual_adc_switch(struct hda_codec *codec)
5847{
5848 struct alc_spec *spec = codec->spec;
5849 init_capsrc_for_pin(codec, spec->ext_mic.pin);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005850 init_capsrc_for_pin(codec, spec->dock_mic.pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005851 init_capsrc_for_pin(codec, spec->int_mic.pin);
5852}
5853
Takashi Iwai584c0c42011-03-10 12:51:11 +01005854/* initialize some special cases for input sources */
5855static void alc_init_special_input_src(struct hda_codec *codec)
5856{
5857 struct alc_spec *spec = codec->spec;
5858 if (spec->dual_adc_switch)
5859 fixup_dual_adc_switch(codec);
5860 else if (spec->single_input_src)
5861 init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
5862}
5863
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005864static void set_capture_mixer(struct hda_codec *codec)
5865{
5866 struct alc_spec *spec = codec->spec;
Takashi Iwaia9111322011-05-02 11:30:18 +02005867 static const struct snd_kcontrol_new *caps[2][3] = {
Takashi Iwaia23b6882009-03-23 15:21:36 +01005868 { alc_capture_mixer_nosrc1,
5869 alc_capture_mixer_nosrc2,
5870 alc_capture_mixer_nosrc3 },
5871 { alc_capture_mixer1,
5872 alc_capture_mixer2,
5873 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005874 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005875 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005876 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005877 int num_adcs = spec->num_adc_nids;
5878 if (spec->dual_adc_switch)
Takashi Iwai584c0c42011-03-10 12:51:11 +01005879 num_adcs = 1;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005880 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005881 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005882 else if (spec->input_mux) {
5883 if (spec->input_mux->num_items > 1)
5884 mux = 1;
5885 else if (spec->input_mux->num_items == 1)
5886 fixup_single_adc(codec);
5887 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005888 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005889 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005890}
5891
Takashi Iwai66946352010-03-29 17:21:45 +02005892/* fill adc_nids (and capsrc_nids) containing all active input pins */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005893static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
Takashi Iwai66946352010-03-29 17:21:45 +02005894 int num_nids)
5895{
5896 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005897 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005898 int n;
5899 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5900
5901 for (n = 0; n < num_nids; n++) {
5902 hda_nid_t adc, cap;
5903 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5904 int nconns, i, j;
5905
5906 adc = nids[n];
5907 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5908 continue;
5909 cap = adc;
5910 nconns = snd_hda_get_connections(codec, cap, conn,
5911 ARRAY_SIZE(conn));
5912 if (nconns == 1) {
5913 cap = conn[0];
5914 nconns = snd_hda_get_connections(codec, cap, conn,
5915 ARRAY_SIZE(conn));
5916 }
5917 if (nconns <= 0)
5918 continue;
5919 if (!fallback_adc) {
5920 fallback_adc = adc;
5921 fallback_cap = cap;
5922 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005923 for (i = 0; i < cfg->num_inputs; i++) {
5924 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005925 for (j = 0; j < nconns; j++) {
5926 if (conn[j] == nid)
5927 break;
5928 }
5929 if (j >= nconns)
5930 break;
5931 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005932 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005933 int num_adcs = spec->num_adc_nids;
5934 spec->private_adc_nids[num_adcs] = adc;
5935 spec->private_capsrc_nids[num_adcs] = cap;
5936 spec->num_adc_nids++;
5937 spec->adc_nids = spec->private_adc_nids;
5938 if (adc != cap)
5939 spec->capsrc_nids = spec->private_capsrc_nids;
5940 }
5941 }
5942 if (!spec->num_adc_nids) {
5943 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005944 " using fallback 0x%x\n",
5945 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005946 spec->private_adc_nids[0] = fallback_adc;
5947 spec->adc_nids = spec->private_adc_nids;
5948 if (fallback_adc != fallback_cap) {
5949 spec->private_capsrc_nids[0] = fallback_cap;
5950 spec->capsrc_nids = spec->private_adc_nids;
5951 }
5952 }
5953}
5954
Takashi Iwai67d634c2009-11-16 15:35:59 +01005955#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005956#define set_beep_amp(spec, nid, idx, dir) \
5957 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005958
Takashi Iwaia9111322011-05-02 11:30:18 +02005959static const struct snd_pci_quirk beep_white_list[] = {
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005960 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005961 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Daniel Corderoa7e985e2011-04-29 08:18:06 +02005962 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
Madis Janson39dfe132011-05-19 18:32:41 +02005963 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005964 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005965 {}
5966};
5967
5968static inline int has_cdefine_beep(struct hda_codec *codec)
5969{
5970 struct alc_spec *spec = codec->spec;
5971 const struct snd_pci_quirk *q;
5972 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5973 if (q)
5974 return q->value;
5975 return spec->cdefine.enable_pcbeep;
5976}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005977#else
5978#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005979#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005980#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005981
5982/*
5983 * OK, here we have finally the patch for ALC880
5984 */
5985
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986static int patch_alc880(struct hda_codec *codec)
5987{
5988 struct alc_spec *spec;
5989 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005990 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005992 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 if (spec == NULL)
5994 return -ENOMEM;
5995
5996 codec->spec = spec;
5997
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005998 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5999 alc880_models,
6000 alc880_cfg_tbl);
6001 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006002 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
6003 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006004 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005 }
6006
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006007 if (board_config == ALC880_AUTO) {
6008 /* automatic parse from the BIOS config */
6009 err = alc880_parse_auto_config(codec);
6010 if (err < 0) {
6011 alc_free(codec);
6012 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006013 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006014 printk(KERN_INFO
6015 "hda_codec: Cannot set up configuration "
6016 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006017 board_config = ALC880_3ST;
6018 }
6019 }
6020
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006021 err = snd_hda_attach_beep_device(codec, 0x1);
6022 if (err < 0) {
6023 alc_free(codec);
6024 return err;
6025 }
6026
Kailang Yangdf694da2005-12-05 19:42:22 +01006027 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02006028 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030 spec->stream_analog_playback = &alc880_pcm_analog_playback;
6031 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006032 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 spec->stream_digital_playback = &alc880_pcm_digital_playback;
6035 spec->stream_digital_capture = &alc880_pcm_digital_capture;
6036
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006037 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006038 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01006039 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006040 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02006041 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006042 if (wcap != AC_WID_AUD_IN) {
6043 spec->adc_nids = alc880_adc_nids_alt;
6044 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006045 } else {
6046 spec->adc_nids = alc880_adc_nids;
6047 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006048 }
6049 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006050 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006051 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052
Takashi Iwai2134ea42008-01-10 16:53:55 +01006053 spec->vmaster_nid = 0x0c;
6054
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006056 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006057 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006058#ifdef CONFIG_SND_HDA_POWER_SAVE
6059 if (!spec->loopback.amplist)
6060 spec->loopback.amplist = alc880_loopbacks;
6061#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062
6063 return 0;
6064}
6065
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006066
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067/*
6068 * ALC260 support
6069 */
6070
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006071static const hda_nid_t alc260_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006072 /* front */
6073 0x02,
6074};
6075
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006076static const hda_nid_t alc260_adc_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006077 /* ADC0 */
6078 0x04,
6079};
6080
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006081static const hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006082 /* ADC1 */
6083 0x05,
6084};
6085
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006086/* NIDs used when simultaneous access to both ADCs makes sense. Note that
6087 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
6088 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006089static const hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006090 /* ADC0, ADC1 */
6091 0x04, 0x05
6092};
6093
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006094#define ALC260_DIGOUT_NID 0x03
6095#define ALC260_DIGIN_NID 0x06
6096
Takashi Iwaia9111322011-05-02 11:30:18 +02006097static const struct hda_input_mux alc260_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006098 .num_items = 4,
6099 .items = {
6100 { "Mic", 0x0 },
6101 { "Front Mic", 0x1 },
6102 { "Line", 0x2 },
6103 { "CD", 0x4 },
6104 },
6105};
6106
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006107/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006108 * headphone jack and the internal CD lines since these are the only pins at
6109 * which audio can appear. For flexibility, also allow the option of
6110 * recording the mixer output on the second ADC (ADC0 doesn't have a
6111 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006112 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006113static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006114 {
6115 .num_items = 3,
6116 .items = {
6117 { "Mic/Line", 0x0 },
6118 { "CD", 0x4 },
6119 { "Headphone", 0x2 },
6120 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006121 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006122 {
6123 .num_items = 4,
6124 .items = {
6125 { "Mic/Line", 0x0 },
6126 { "CD", 0x4 },
6127 { "Headphone", 0x2 },
6128 { "Mixer", 0x5 },
6129 },
6130 },
6131
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006132};
6133
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006134/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
6135 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006136 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006137static const struct hda_input_mux alc260_acer_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006138 {
6139 .num_items = 4,
6140 .items = {
6141 { "Mic", 0x0 },
6142 { "Line", 0x2 },
6143 { "CD", 0x4 },
6144 { "Headphone", 0x5 },
6145 },
6146 },
6147 {
6148 .num_items = 5,
6149 .items = {
6150 { "Mic", 0x0 },
6151 { "Line", 0x2 },
6152 { "CD", 0x4 },
6153 { "Headphone", 0x6 },
6154 { "Mixer", 0x5 },
6155 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006156 },
6157};
Michael Schwingencc959482009-02-22 18:58:45 +01006158
6159/* Maxdata Favorit 100XS */
Takashi Iwaia9111322011-05-02 11:30:18 +02006160static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006161 {
6162 .num_items = 2,
6163 .items = {
6164 { "Line/Mic", 0x0 },
6165 { "CD", 0x4 },
6166 },
6167 },
6168 {
6169 .num_items = 3,
6170 .items = {
6171 { "Line/Mic", 0x0 },
6172 { "CD", 0x4 },
6173 { "Mixer", 0x5 },
6174 },
6175 },
6176};
6177
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178/*
6179 * This is just place-holder, so there's something for alc_build_pcms to look
6180 * at when it calculates the maximum number of channels. ALC260 has no mixer
6181 * element which allows changing the channel mode, so the verb list is
6182 * never used.
6183 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006184static const struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 { 2, NULL },
6186};
6187
Kailang Yangdf694da2005-12-05 19:42:22 +01006188
6189/* Mixer combinations
6190 *
6191 * basic: base_output + input + pc_beep + capture
6192 * HP: base_output + input + capture_alt
6193 * HP_3013: hp_3013 + input + capture
6194 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006195 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01006196 */
6197
Takashi Iwaia9111322011-05-02 11:30:18 +02006198static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006199 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006200 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006201 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6202 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6203 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6204 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6205 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006206};
Kailang Yangdf694da2005-12-05 19:42:22 +01006207
Takashi Iwaia9111322011-05-02 11:30:18 +02006208static const struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6210 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6211 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6212 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6213 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6214 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6215 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
6216 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 { } /* end */
6218};
6219
Takashi Iwaibec15c32008-01-28 18:16:30 +01006220/* update HP, line and mono out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +02006221static void alc260_hp_master_update(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006222{
Takashi Iwaie9427962011-04-28 15:46:07 +02006223 update_speakers(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006224}
6225
6226static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
6227 struct snd_ctl_elem_value *ucontrol)
6228{
6229 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6230 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006231 *ucontrol->value.integer.value = !spec->master_mute;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006232 return 0;
6233}
6234
6235static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
6236 struct snd_ctl_elem_value *ucontrol)
6237{
6238 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6239 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006240 int val = !*ucontrol->value.integer.value;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006241
Takashi Iwaie9427962011-04-28 15:46:07 +02006242 if (val == spec->master_mute)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006243 return 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02006244 spec->master_mute = val;
6245 alc260_hp_master_update(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006246 return 1;
6247}
6248
Takashi Iwaia9111322011-05-02 11:30:18 +02006249static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006250 {
6251 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6252 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006253 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006254 .info = snd_ctl_boolean_mono_info,
6255 .get = alc260_hp_master_sw_get,
6256 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006257 },
6258 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6259 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
6260 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6261 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6262 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
6263 HDA_OUTPUT),
6264 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6265 { } /* end */
6266};
6267
Takashi Iwaia9111322011-05-02 11:30:18 +02006268static const struct hda_verb alc260_hp_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006269 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6270 {},
6271};
6272
Takashi Iwaie9427962011-04-28 15:46:07 +02006273static void alc260_hp_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006274{
6275 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006276
Takashi Iwaie9427962011-04-28 15:46:07 +02006277 spec->autocfg.hp_pins[0] = 0x0f;
6278 spec->autocfg.speaker_pins[0] = 0x10;
6279 spec->autocfg.speaker_pins[1] = 0x11;
6280 spec->automute = 1;
6281 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006282}
6283
Takashi Iwaia9111322011-05-02 11:30:18 +02006284static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006285 {
6286 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6287 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006288 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006289 .info = snd_ctl_boolean_mono_info,
6290 .get = alc260_hp_master_sw_get,
6291 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006292 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006293 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6294 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6295 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6296 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6297 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6298 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006299 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6300 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006301 { } /* end */
6302};
6303
Takashi Iwaie9427962011-04-28 15:46:07 +02006304static void alc260_hp_3013_setup(struct hda_codec *codec)
6305{
6306 struct alc_spec *spec = codec->spec;
6307
6308 spec->autocfg.hp_pins[0] = 0x15;
6309 spec->autocfg.speaker_pins[0] = 0x10;
6310 spec->autocfg.speaker_pins[1] = 0x11;
6311 spec->automute = 1;
6312 spec->automute_mode = ALC_AUTOMUTE_PIN;
6313}
6314
Takashi Iwaia9111322011-05-02 11:30:18 +02006315static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
Kailang Yang3f878302008-08-26 13:02:23 +02006316 .ops = &snd_hda_bind_vol,
6317 .values = {
6318 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6319 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6320 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6321 0
6322 },
6323};
6324
Takashi Iwaia9111322011-05-02 11:30:18 +02006325static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
Kailang Yang3f878302008-08-26 13:02:23 +02006326 .ops = &snd_hda_bind_sw,
6327 .values = {
6328 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6329 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6330 0
6331 },
6332};
6333
Takashi Iwaia9111322011-05-02 11:30:18 +02006334static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006335 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6336 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6337 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6338 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6339 { } /* end */
6340};
6341
Takashi Iwaia9111322011-05-02 11:30:18 +02006342static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006343 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6344 {},
6345};
6346
Takashi Iwaie9427962011-04-28 15:46:07 +02006347static void alc260_hp_3012_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006348{
6349 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006350
Takashi Iwaie9427962011-04-28 15:46:07 +02006351 spec->autocfg.hp_pins[0] = 0x10;
6352 spec->autocfg.speaker_pins[0] = 0x0f;
6353 spec->autocfg.speaker_pins[1] = 0x11;
6354 spec->autocfg.speaker_pins[2] = 0x15;
6355 spec->automute = 1;
6356 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang3f878302008-08-26 13:02:23 +02006357}
6358
6359/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006360 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6361 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006362static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006363 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006364 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006365 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006366 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6367 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6368 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6369 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006370 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006371 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6372 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006373 { } /* end */
6374};
6375
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006376/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6377 * versions of the ALC260 don't act on requests to enable mic bias from NID
6378 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6379 * datasheet doesn't mention this restriction. At this stage it's not clear
6380 * whether this behaviour is intentional or is a hardware bug in chip
6381 * revisions available in early 2006. Therefore for now allow the
6382 * "Headphone Jack Mode" control to span all choices, but if it turns out
6383 * that the lack of mic bias for this NID is intentional we could change the
6384 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6385 *
6386 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6387 * don't appear to make the mic bias available from the "line" jack, even
6388 * though the NID used for this jack (0x14) can supply it. The theory is
6389 * that perhaps Acer have included blocking capacitors between the ALC260
6390 * and the output jack. If this turns out to be the case for all such
6391 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6392 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006393 *
6394 * The C20x Tablet series have a mono internal speaker which is controlled
6395 * via the chip's Mono sum widget and pin complex, so include the necessary
6396 * controls for such models. On models without a "mono speaker" the control
6397 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006398 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006399static const struct snd_kcontrol_new alc260_acer_mixer[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006400 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6401 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006402 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006403 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006404 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006405 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006406 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006407 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6408 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6409 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6410 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6411 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6412 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6413 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6414 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006415 { } /* end */
6416};
6417
Michael Schwingencc959482009-02-22 18:58:45 +01006418/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6419 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006420static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006421 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6422 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6423 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6424 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6425 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6426 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6427 { } /* end */
6428};
6429
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006430/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6431 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6432 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006433static const struct snd_kcontrol_new alc260_will_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006434 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6435 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6436 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6437 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6438 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6439 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6440 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6441 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6442 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6443 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006444 { } /* end */
6445};
6446
6447/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6448 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6449 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006450static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006451 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6452 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6453 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6454 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6455 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6456 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6457 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6458 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6459 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6460 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6461 { } /* end */
6462};
6463
Kailang Yangdf694da2005-12-05 19:42:22 +01006464/*
6465 * initialization verbs
6466 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006467static const struct hda_verb alc260_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006469 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006471 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006473 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006475 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006477 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006479 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006481 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006482 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006483 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006485 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6486 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006487 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006488 /* set connection select to line in (default select for this ADC) */
6489 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006490 /* mute capture amp left and right */
6491 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6492 /* set connection select to line in (default select for this ADC) */
6493 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006494 /* set vol=0 Line-Out mixer amp left and right */
6495 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6496 /* unmute pin widget amp left and right (no gain on this amp) */
6497 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6498 /* set vol=0 HP mixer amp left and right */
6499 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6500 /* unmute pin widget amp left and right (no gain on this amp) */
6501 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6502 /* set vol=0 Mono mixer amp left and right */
6503 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6504 /* unmute pin widget amp left and right (no gain on this amp) */
6505 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6506 /* unmute LINE-2 out pin */
6507 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006508 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6509 * Line In 2 = 0x03
6510 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006511 /* mute analog inputs */
6512 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6513 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6514 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6515 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6516 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006518 /* mute Front out path */
6519 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6520 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6521 /* mute Headphone out path */
6522 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6523 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6524 /* mute Mono out path */
6525 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6526 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527 { }
6528};
6529
Takashi Iwai474167d2006-05-17 17:17:43 +02006530#if 0 /* should be identical with alc260_init_verbs? */
Takashi Iwaia9111322011-05-02 11:30:18 +02006531static const struct hda_verb alc260_hp_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006532 /* Headphone and output */
6533 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6534 /* mono output */
6535 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6536 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6537 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6538 /* Mic2 (front panel) pin widget for input and vref at 80% */
6539 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6540 /* Line In pin widget for input */
6541 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6542 /* Line-2 pin widget for output */
6543 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6544 /* CD pin widget for input */
6545 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6546 /* unmute amp left and right */
6547 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6548 /* set connection select to line in (default select for this ADC) */
6549 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6550 /* unmute Line-Out mixer amp left and right (volume = 0) */
6551 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6552 /* mute pin widget amp left and right (no gain on this amp) */
6553 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6554 /* unmute HP mixer amp left and right (volume = 0) */
6555 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6556 /* mute pin widget amp left and right (no gain on this amp) */
6557 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006558 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6559 * Line In 2 = 0x03
6560 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006561 /* mute analog inputs */
6562 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6563 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6564 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6565 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6566 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006567 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6568 /* Unmute Front out path */
6569 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6570 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6571 /* Unmute Headphone out path */
6572 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6573 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6574 /* Unmute Mono out path */
6575 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6576 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6577 { }
6578};
Takashi Iwai474167d2006-05-17 17:17:43 +02006579#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006580
Takashi Iwaia9111322011-05-02 11:30:18 +02006581static const struct hda_verb alc260_hp_3013_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006582 /* Line out and output */
6583 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6584 /* mono output */
6585 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6586 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6587 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6588 /* Mic2 (front panel) pin widget for input and vref at 80% */
6589 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6590 /* Line In pin widget for input */
6591 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6592 /* Headphone pin widget for output */
6593 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6594 /* CD pin widget for input */
6595 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6596 /* unmute amp left and right */
6597 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6598 /* set connection select to line in (default select for this ADC) */
6599 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6600 /* unmute Line-Out mixer amp left and right (volume = 0) */
6601 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6602 /* mute pin widget amp left and right (no gain on this amp) */
6603 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6604 /* unmute HP mixer amp left and right (volume = 0) */
6605 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6606 /* mute pin widget amp left and right (no gain on this amp) */
6607 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006608 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6609 * Line In 2 = 0x03
6610 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006611 /* mute analog inputs */
6612 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6613 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6614 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6615 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6616 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006617 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6618 /* Unmute Front out path */
6619 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6620 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6621 /* Unmute Headphone out path */
6622 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6623 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6624 /* Unmute Mono out path */
6625 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6626 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6627 { }
6628};
6629
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006630/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006631 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6632 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006633 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006634static const struct hda_verb alc260_fujitsu_init_verbs[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006635 /* Disable all GPIOs */
6636 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6637 /* Internal speaker is connected to headphone pin */
6638 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6639 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6640 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006641 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6642 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6643 /* Ensure all other unused pins are disabled and muted. */
6644 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6645 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006646 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006647 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006648 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006649 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6650 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6651 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006652
Jonathan Woithef7ace402006-02-28 11:46:14 +01006653 /* Disable digital (SPDIF) pins */
6654 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6655 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006656
Kailang Yangea1fb292008-08-26 12:58:38 +02006657 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006658 * when acting as an output.
6659 */
6660 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6661
6662 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006663 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6664 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6665 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6666 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6667 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6668 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6669 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6670 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6671 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006672
Jonathan Woithef7ace402006-02-28 11:46:14 +01006673 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6674 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6675 /* Unmute Line1 pin widget output buffer since it starts as an output.
6676 * If the pin mode is changed by the user the pin mode control will
6677 * take care of enabling the pin's input/output buffers as needed.
6678 * Therefore there's no need to enable the input buffer at this
6679 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006680 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006681 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006682 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006683 * mixer ctrl)
6684 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006685 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006686
Jonathan Woithef7ace402006-02-28 11:46:14 +01006687 /* Mute capture amp left and right */
6688 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006689 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006690 * in (on mic1 pin)
6691 */
6692 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006693
Jonathan Woithef7ace402006-02-28 11:46:14 +01006694 /* Do the same for the second ADC: mute capture input amp and
6695 * set ADC connection to line in (on mic1 pin)
6696 */
6697 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6698 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006699
Jonathan Woithef7ace402006-02-28 11:46:14 +01006700 /* Mute all inputs to mixer widget (even unconnected ones) */
6701 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6702 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6703 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6704 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6705 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6706 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6707 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6708 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006709
6710 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006711};
6712
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006713/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6714 * similar laptops (adapted from Fujitsu init verbs).
6715 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006716static const struct hda_verb alc260_acer_init_verbs[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006717 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6718 * the headphone jack. Turn this on and rely on the standard mute
6719 * methods whenever the user wants to turn these outputs off.
6720 */
6721 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6722 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6723 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6724 /* Internal speaker/Headphone jack is connected to Line-out pin */
6725 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6726 /* Internal microphone/Mic jack is connected to Mic1 pin */
6727 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6728 /* Line In jack is connected to Line1 pin */
6729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006730 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6731 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006732 /* Ensure all other unused pins are disabled and muted. */
6733 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6734 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006735 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6736 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6737 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6738 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6739 /* Disable digital (SPDIF) pins */
6740 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6741 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6742
Kailang Yangea1fb292008-08-26 12:58:38 +02006743 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006744 * bus when acting as outputs.
6745 */
6746 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6747 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6748
6749 /* Start with output sum widgets muted and their output gains at min */
6750 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6751 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6752 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6753 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6754 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6755 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6756 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6757 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6758 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6759
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006760 /* Unmute Line-out pin widget amp left and right
6761 * (no equiv mixer ctrl)
6762 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006763 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006764 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6765 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006766 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6767 * inputs. If the pin mode is changed by the user the pin mode control
6768 * will take care of enabling the pin's input/output buffers as needed.
6769 * Therefore there's no need to enable the input buffer at this
6770 * stage.
6771 */
6772 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6773 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6774
6775 /* Mute capture amp left and right */
6776 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6777 /* Set ADC connection select to match default mixer setting - mic
6778 * (on mic1 pin)
6779 */
6780 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6781
6782 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006783 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006784 */
6785 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006786 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006787
6788 /* Mute all inputs to mixer widget (even unconnected ones) */
6789 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6792 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6793 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6794 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6795 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6796 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6797
6798 { }
6799};
6800
Michael Schwingencc959482009-02-22 18:58:45 +01006801/* Initialisation sequence for Maxdata Favorit 100XS
6802 * (adapted from Acer init verbs).
6803 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006804static const struct hda_verb alc260_favorit100_init_verbs[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006805 /* GPIO 0 enables the output jack.
6806 * Turn this on and rely on the standard mute
6807 * methods whenever the user wants to turn these outputs off.
6808 */
6809 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6810 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6811 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6812 /* Line/Mic input jack is connected to Mic1 pin */
6813 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6814 /* Ensure all other unused pins are disabled and muted. */
6815 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6816 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6817 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6818 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6819 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6820 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6821 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6822 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6823 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6824 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6825 /* Disable digital (SPDIF) pins */
6826 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6827 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6828
6829 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6830 * bus when acting as outputs.
6831 */
6832 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6833 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6834
6835 /* Start with output sum widgets muted and their output gains at min */
6836 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6837 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6838 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6839 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6840 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6841 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6842 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6843 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6844 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6845
6846 /* Unmute Line-out pin widget amp left and right
6847 * (no equiv mixer ctrl)
6848 */
6849 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6850 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6851 * inputs. If the pin mode is changed by the user the pin mode control
6852 * will take care of enabling the pin's input/output buffers as needed.
6853 * Therefore there's no need to enable the input buffer at this
6854 * stage.
6855 */
6856 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6857
6858 /* Mute capture amp left and right */
6859 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6860 /* Set ADC connection select to match default mixer setting - mic
6861 * (on mic1 pin)
6862 */
6863 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6864
6865 /* Do similar with the second ADC: mute capture input amp and
6866 * set ADC connection to mic to match ALSA's default state.
6867 */
6868 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6869 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6870
6871 /* Mute all inputs to mixer widget (even unconnected ones) */
6872 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6873 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6874 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6875 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6876 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6878 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6879 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6880
6881 { }
6882};
6883
Takashi Iwaia9111322011-05-02 11:30:18 +02006884static const struct hda_verb alc260_will_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006885 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6886 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6887 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6888 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6889 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6890 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6891 {}
6892};
6893
Takashi Iwaia9111322011-05-02 11:30:18 +02006894static const struct hda_verb alc260_replacer_672v_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006895 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6896 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6897 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6898
6899 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6900 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6901 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6902
6903 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6904 {}
6905};
6906
6907/* toggle speaker-output according to the hp-jack state */
6908static void alc260_replacer_672v_automute(struct hda_codec *codec)
6909{
6910 unsigned int present;
6911
6912 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006913 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006914 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006915 snd_hda_codec_write_cache(codec, 0x01, 0,
6916 AC_VERB_SET_GPIO_DATA, 1);
6917 snd_hda_codec_write_cache(codec, 0x0f, 0,
6918 AC_VERB_SET_PIN_WIDGET_CONTROL,
6919 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006920 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006921 snd_hda_codec_write_cache(codec, 0x01, 0,
6922 AC_VERB_SET_GPIO_DATA, 0);
6923 snd_hda_codec_write_cache(codec, 0x0f, 0,
6924 AC_VERB_SET_PIN_WIDGET_CONTROL,
6925 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006926 }
6927}
6928
6929static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6930 unsigned int res)
6931{
6932 if ((res >> 26) == ALC880_HP_EVENT)
6933 alc260_replacer_672v_automute(codec);
6934}
6935
Takashi Iwaia9111322011-05-02 11:30:18 +02006936static const struct hda_verb alc260_hp_dc7600_verbs[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006937 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6938 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6939 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6940 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6941 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6942 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6943 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6944 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6945 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6946 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6947 {}
6948};
6949
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006950/* Test configuration for debugging, modelled after the ALC880 test
6951 * configuration.
6952 */
6953#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006954static const hda_nid_t alc260_test_dac_nids[1] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006955 0x02,
6956};
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006957static const hda_nid_t alc260_test_adc_nids[2] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006958 0x04, 0x05,
6959};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006960/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006961 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006962 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006963 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006964static const struct hda_input_mux alc260_test_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006965 {
6966 .num_items = 7,
6967 .items = {
6968 { "MIC1 pin", 0x0 },
6969 { "MIC2 pin", 0x1 },
6970 { "LINE1 pin", 0x2 },
6971 { "LINE2 pin", 0x3 },
6972 { "CD pin", 0x4 },
6973 { "LINE-OUT pin", 0x5 },
6974 { "HP-OUT pin", 0x6 },
6975 },
6976 },
6977 {
6978 .num_items = 8,
6979 .items = {
6980 { "MIC1 pin", 0x0 },
6981 { "MIC2 pin", 0x1 },
6982 { "LINE1 pin", 0x2 },
6983 { "LINE2 pin", 0x3 },
6984 { "CD pin", 0x4 },
6985 { "Mixer", 0x5 },
6986 { "LINE-OUT pin", 0x6 },
6987 { "HP-OUT pin", 0x7 },
6988 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006989 },
6990};
Takashi Iwaia9111322011-05-02 11:30:18 +02006991static const struct snd_kcontrol_new alc260_test_mixer[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006992 /* Output driver widgets */
6993 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6994 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6995 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6996 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6997 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6998 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6999
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007000 /* Modes for retasking pin widgets
7001 * Note: the ALC260 doesn't seem to act on requests to enable mic
7002 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
7003 * mention this restriction. At this stage it's not clear whether
7004 * this behaviour is intentional or is a hardware bug in chip
7005 * revisions available at least up until early 2006. Therefore for
7006 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
7007 * choices, but if it turns out that the lack of mic bias for these
7008 * NIDs is intentional we could change their modes from
7009 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
7010 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007011 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
7012 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
7013 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
7014 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
7015 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
7016 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
7017
7018 /* Loopback mixer controls */
7019 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
7020 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
7021 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
7022 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
7023 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
7024 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
7025 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
7026 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
7027 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
7028 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007029 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
7030 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
7031 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
7032 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01007033
7034 /* Controls for GPIO pins, assuming they are configured as outputs */
7035 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
7036 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
7037 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
7038 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
7039
Jonathan Woithe92621f12006-02-28 11:47:47 +01007040 /* Switches to allow the digital IO pins to be enabled. The datasheet
7041 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02007042 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01007043 */
7044 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
7045 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
7046
Jonathan Woithef8225f62008-01-08 12:16:54 +01007047 /* A switch allowing EAPD to be enabled. Some laptops seem to use
7048 * this output to turn on an external amplifier.
7049 */
7050 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
7051 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
7052
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007053 { } /* end */
7054};
Takashi Iwaia9111322011-05-02 11:30:18 +02007055static const struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01007056 /* Enable all GPIOs as outputs with an initial value of 0 */
7057 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
7058 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
7059 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
7060
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007061 /* Enable retasking pins as output, initially without power amp */
7062 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7063 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7064 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7065 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7066 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7067 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7068
Jonathan Woithe92621f12006-02-28 11:47:47 +01007069 /* Disable digital (SPDIF) pins initially, but users can enable
7070 * them via a mixer switch. In the case of SPDIF-out, this initverb
7071 * payload also sets the generation to 0, output to be in "consumer"
7072 * PCM format, copyright asserted, no pre-emphasis and no validity
7073 * control.
7074 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007075 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
7076 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
7077
Kailang Yangea1fb292008-08-26 12:58:38 +02007078 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007079 * OUT1 sum bus when acting as an output.
7080 */
7081 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
7082 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
7083 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
7084 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
7085
7086 /* Start with output sum widgets muted and their output gains at min */
7087 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7088 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7089 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7090 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7091 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7092 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7093 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7094 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7095 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7096
Jonathan Woithecdcd9262006-02-28 11:36:42 +01007097 /* Unmute retasking pin widget output buffers since the default
7098 * state appears to be output. As the pin mode is changed by the
7099 * user the pin mode control will take care of enabling the pin's
7100 * input/output buffers as needed.
7101 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007102 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7103 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7104 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7105 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7106 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7107 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7108 /* Also unmute the mono-out pin widget */
7109 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7110
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007111 /* Mute capture amp left and right */
7112 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01007113 /* Set ADC connection select to match default mixer setting (mic1
7114 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007115 */
7116 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7117
7118 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01007119 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007120 */
7121 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7122 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7123
7124 /* Mute all inputs to mixer widget (even unconnected ones) */
7125 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
7126 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
7127 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
7128 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
7129 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
7130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
7131 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
7132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
7133
7134 { }
7135};
7136#endif
7137
Takashi Iwai63300792008-01-24 15:31:36 +01007138#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
7139#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07007140
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007141#define alc260_pcm_digital_playback alc880_pcm_digital_playback
7142#define alc260_pcm_digital_capture alc880_pcm_digital_capture
7143
Kailang Yangdf694da2005-12-05 19:42:22 +01007144/*
7145 * for BIOS auto-configuration
7146 */
7147
7148static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02007149 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01007150{
7151 hda_nid_t nid_vol;
7152 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01007153 int err;
7154
7155 if (nid >= 0x0f && nid < 0x11) {
7156 nid_vol = nid - 0x7;
7157 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
7158 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
7159 } else if (nid == 0x11) {
7160 nid_vol = nid - 0x7;
7161 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
7162 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
7163 } else if (nid >= 0x12 && nid <= 0x15) {
7164 nid_vol = 0x08;
7165 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
7166 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
7167 } else
7168 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02007169
Takashi Iwai863b4512008-10-21 17:01:47 +02007170 if (!(*vol_bits & (1 << nid_vol))) {
7171 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007172 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02007173 if (err < 0)
7174 return err;
7175 *vol_bits |= (1 << nid_vol);
7176 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007177 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007178 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007179 return err;
7180 return 1;
7181}
7182
7183/* add playback controls from the parsed DAC table */
7184static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
7185 const struct auto_pin_cfg *cfg)
7186{
7187 hda_nid_t nid;
7188 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02007189 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007190
7191 spec->multiout.num_dacs = 1;
7192 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +02007193 spec->private_dac_nids[0] = 0x02;
Kailang Yangdf694da2005-12-05 19:42:22 +01007194
7195 nid = cfg->line_out_pins[0];
7196 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02007197 const char *pfx;
7198 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
7199 pfx = "Master";
7200 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
7201 pfx = "Speaker";
7202 else
7203 pfx = "Front";
7204 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007205 if (err < 0)
7206 return err;
7207 }
7208
Takashi Iwai82bc9552006-03-21 11:24:42 +01007209 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007210 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007211 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007212 if (err < 0)
7213 return err;
7214 }
7215
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007216 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007217 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007218 err = alc260_add_playback_controls(spec, nid, "Headphone",
7219 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007220 if (err < 0)
7221 return err;
7222 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007223 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007224}
7225
7226/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007227static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01007228 const struct auto_pin_cfg *cfg)
7229{
Takashi Iwai05f5f472009-08-25 13:10:18 +02007230 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01007231}
7232
7233static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
7234 hda_nid_t nid, int pin_type,
7235 int sel_idx)
7236{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007237 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007238 /* need the manual connection? */
7239 if (nid >= 0x12) {
7240 int idx = nid - 0x12;
7241 snd_hda_codec_write(codec, idx + 0x0b, 0,
7242 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01007243 }
7244}
7245
7246static void alc260_auto_init_multi_out(struct hda_codec *codec)
7247{
7248 struct alc_spec *spec = codec->spec;
7249 hda_nid_t nid;
7250
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007251 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007252 if (nid) {
7253 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7254 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7255 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007256
Takashi Iwai82bc9552006-03-21 11:24:42 +01007257 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007258 if (nid)
7259 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7260
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007261 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007262 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007263 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007264}
Kailang Yangdf694da2005-12-05 19:42:22 +01007265
7266#define ALC260_PIN_CD_NID 0x16
7267static void alc260_auto_init_analog_input(struct hda_codec *codec)
7268{
7269 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007270 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01007271 int i;
7272
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007273 for (i = 0; i < cfg->num_inputs; i++) {
7274 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01007275 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02007276 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01007277 if (nid != ALC260_PIN_CD_NID &&
7278 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007279 snd_hda_codec_write(codec, nid, 0,
7280 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01007281 AMP_OUT_MUTE);
7282 }
7283 }
7284}
7285
Takashi Iwai7f311a42010-04-09 17:32:23 +02007286#define alc260_auto_init_input_src alc880_auto_init_input_src
7287
Kailang Yangdf694da2005-12-05 19:42:22 +01007288/*
7289 * generic initialization of ADC, input mixers and output mixers
7290 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007291static const struct hda_verb alc260_volume_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007292 /*
7293 * Unmute ADC0-1 and set the default input to mic-in
7294 */
7295 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7296 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7297 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7298 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007299
Kailang Yangdf694da2005-12-05 19:42:22 +01007300 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
7301 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007302 * Note: PASD motherboards uses the Line In 2 as the input for
7303 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01007304 */
7305 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007306 /* mute analog inputs */
7307 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7308 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7309 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7310 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7311 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007312
7313 /*
7314 * Set up output mixers (0x08 - 0x0a)
7315 */
7316 /* set vol=0 to output mixers */
7317 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7318 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7319 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7320 /* set up input amps for analog loopback */
7321 /* Amp Indices: DAC = 0, mixer = 1 */
7322 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7323 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7324 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7325 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7326 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7327 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007328
Kailang Yangdf694da2005-12-05 19:42:22 +01007329 { }
7330};
7331
7332static int alc260_parse_auto_config(struct hda_codec *codec)
7333{
7334 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007335 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007336 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +01007337
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007338 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7339 alc260_ignore);
7340 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007341 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007342 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7343 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007344 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007345 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007346 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007347 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007348 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007349 return err;
7350
7351 spec->multiout.max_channels = 2;
7352
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007353 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007354 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007355 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007356 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007357
Takashi Iwaid88897e2008-10-31 15:01:37 +01007358 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01007359
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007360 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007361 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007362
Kailang Yang6227cdc2010-02-25 08:36:52 +01007363 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007364
Kailang Yangdf694da2005-12-05 19:42:22 +01007365 return 1;
7366}
7367
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007368/* additional initialization for auto-configuration model */
7369static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007370{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007371 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007372 alc260_auto_init_multi_out(codec);
7373 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02007374 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007375 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007376 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007377 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007378}
7379
Takashi Iwaicb53c622007-08-10 17:21:45 +02007380#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02007381static const struct hda_amp_list alc260_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02007382 { 0x07, HDA_INPUT, 0 },
7383 { 0x07, HDA_INPUT, 1 },
7384 { 0x07, HDA_INPUT, 2 },
7385 { 0x07, HDA_INPUT, 3 },
7386 { 0x07, HDA_INPUT, 4 },
7387 { } /* end */
7388};
7389#endif
7390
Kailang Yangdf694da2005-12-05 19:42:22 +01007391/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007392 * Pin config fixes
7393 */
7394enum {
7395 PINFIX_HP_DC5750,
7396};
7397
Takashi Iwaifc091762010-08-04 23:53:36 +02007398static const struct alc_fixup alc260_fixups[] = {
7399 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007400 .type = ALC_FIXUP_PINS,
7401 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007402 { 0x11, 0x90130110 }, /* speaker */
7403 { }
7404 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007405 },
7406};
7407
Takashi Iwaia9111322011-05-02 11:30:18 +02007408static const struct snd_pci_quirk alc260_fixup_tbl[] = {
Takashi Iwaifc091762010-08-04 23:53:36 +02007409 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7410 {}
7411};
7412
7413/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007414 * ALC260 configurations
7415 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007416static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007417 [ALC260_BASIC] = "basic",
7418 [ALC260_HP] = "hp",
7419 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007420 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007421 [ALC260_FUJITSU_S702X] = "fujitsu",
7422 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007423 [ALC260_WILL] = "will",
7424 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007425 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007426#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007427 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007428#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007429 [ALC260_AUTO] = "auto",
7430};
7431
Takashi Iwaia9111322011-05-02 11:30:18 +02007432static const struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007433 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007434 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007435 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007436 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007437 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007438 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007439 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007440 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007441 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007442 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7443 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7444 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7445 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7446 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7447 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7448 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7449 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7450 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007451 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007452 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007453 {}
7454};
7455
Takashi Iwaia9111322011-05-02 11:30:18 +02007456static const struct alc_config_preset alc260_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007457 [ALC260_BASIC] = {
7458 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007459 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007460 .init_verbs = { alc260_init_verbs },
7461 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7462 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007463 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007464 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007465 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7466 .channel_mode = alc260_modes,
7467 .input_mux = &alc260_capture_source,
7468 },
7469 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007470 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007471 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007472 .init_verbs = { alc260_init_verbs,
7473 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007474 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7475 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007476 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7477 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007478 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7479 .channel_mode = alc260_modes,
7480 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007481 .unsol_event = alc_sku_unsol_event,
7482 .setup = alc260_hp_setup,
7483 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007484 },
Kailang Yang3f878302008-08-26 13:02:23 +02007485 [ALC260_HP_DC7600] = {
7486 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007487 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007488 .init_verbs = { alc260_init_verbs,
7489 alc260_hp_dc7600_verbs },
7490 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7491 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007492 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7493 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007494 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7495 .channel_mode = alc260_modes,
7496 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007497 .unsol_event = alc_sku_unsol_event,
7498 .setup = alc260_hp_3012_setup,
7499 .init_hook = alc_inithook,
Kailang Yang3f878302008-08-26 13:02:23 +02007500 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007501 [ALC260_HP_3013] = {
7502 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007503 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007504 .init_verbs = { alc260_hp_3013_init_verbs,
7505 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007506 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7507 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007508 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7509 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007510 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7511 .channel_mode = alc260_modes,
7512 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007513 .unsol_event = alc_sku_unsol_event,
7514 .setup = alc260_hp_3013_setup,
7515 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007516 },
7517 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007518 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007519 .init_verbs = { alc260_fujitsu_init_verbs },
7520 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7521 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007522 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7523 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007524 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7525 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007526 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7527 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007528 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007529 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007530 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007531 .init_verbs = { alc260_acer_init_verbs },
7532 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7533 .dac_nids = alc260_dac_nids,
7534 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7535 .adc_nids = alc260_dual_adc_nids,
7536 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7537 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007538 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7539 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007540 },
Michael Schwingencc959482009-02-22 18:58:45 +01007541 [ALC260_FAVORIT100] = {
7542 .mixers = { alc260_favorit100_mixer },
7543 .init_verbs = { alc260_favorit100_init_verbs },
7544 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7545 .dac_nids = alc260_dac_nids,
7546 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7547 .adc_nids = alc260_dual_adc_nids,
7548 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7549 .channel_mode = alc260_modes,
7550 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7551 .input_mux = alc260_favorit100_capture_sources,
7552 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007553 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007554 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007555 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7556 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7557 .dac_nids = alc260_dac_nids,
7558 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7559 .adc_nids = alc260_adc_nids,
7560 .dig_out_nid = ALC260_DIGOUT_NID,
7561 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7562 .channel_mode = alc260_modes,
7563 .input_mux = &alc260_capture_source,
7564 },
7565 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007566 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007567 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7568 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7569 .dac_nids = alc260_dac_nids,
7570 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7571 .adc_nids = alc260_adc_nids,
7572 .dig_out_nid = ALC260_DIGOUT_NID,
7573 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7574 .channel_mode = alc260_modes,
7575 .input_mux = &alc260_capture_source,
7576 .unsol_event = alc260_replacer_672v_unsol_event,
7577 .init_hook = alc260_replacer_672v_automute,
7578 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007579#ifdef CONFIG_SND_DEBUG
7580 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007581 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007582 .init_verbs = { alc260_test_init_verbs },
7583 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7584 .dac_nids = alc260_test_dac_nids,
7585 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7586 .adc_nids = alc260_test_adc_nids,
7587 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7588 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007589 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7590 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007591 },
7592#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007593};
7594
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595static int patch_alc260(struct hda_codec *codec)
7596{
7597 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007598 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007599
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007600 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601 if (spec == NULL)
7602 return -ENOMEM;
7603
7604 codec->spec = spec;
7605
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007606 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7607 alc260_models,
7608 alc260_cfg_tbl);
7609 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007610 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007611 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007612 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007613 }
7614
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007615 if (board_config == ALC260_AUTO) {
7616 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7617 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7618 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007619
Kailang Yangdf694da2005-12-05 19:42:22 +01007620 if (board_config == ALC260_AUTO) {
7621 /* automatic parse from the BIOS config */
7622 err = alc260_parse_auto_config(codec);
7623 if (err < 0) {
7624 alc_free(codec);
7625 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007626 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007627 printk(KERN_INFO
7628 "hda_codec: Cannot set up configuration "
7629 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007630 board_config = ALC260_BASIC;
7631 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007634 err = snd_hda_attach_beep_device(codec, 0x1);
7635 if (err < 0) {
7636 alc_free(codec);
7637 return err;
7638 }
7639
Kailang Yangdf694da2005-12-05 19:42:22 +01007640 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007641 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7644 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307645 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007647 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7648 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7649
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007650 if (!spec->adc_nids && spec->input_mux) {
7651 /* check whether NID 0x04 is valid */
7652 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007653 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007654 /* get type */
7655 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7656 spec->adc_nids = alc260_adc_nids_alt;
7657 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7658 } else {
7659 spec->adc_nids = alc260_adc_nids;
7660 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7661 }
7662 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007663 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007664 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007665
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007666 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007667
Takashi Iwai2134ea42008-01-10 16:53:55 +01007668 spec->vmaster_nid = 0x08;
7669
Linus Torvalds1da177e2005-04-16 15:20:36 -07007670 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007671 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007672 spec->init_hook = alc260_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +02007673 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007674#ifdef CONFIG_SND_HDA_POWER_SAVE
7675 if (!spec->loopback.amplist)
7676 spec->loopback.amplist = alc260_loopbacks;
7677#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678
7679 return 0;
7680}
7681
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007682
Linus Torvalds1da177e2005-04-16 15:20:36 -07007683/*
Takashi Iwai49535502009-06-30 15:28:30 +02007684 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685 *
7686 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7687 * configuration. Each pin widget can choose any input DACs and a mixer.
7688 * Each ADC is connected from a mixer of all inputs. This makes possible
7689 * 6-channel independent captures.
7690 *
7691 * In addition, an independent DAC for the multi-playback (not used in this
7692 * driver yet).
7693 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007694#define ALC882_DIGOUT_NID 0x06
7695#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007696#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7697#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7698#define ALC1200_DIGOUT_NID 0x10
7699
Linus Torvalds1da177e2005-04-16 15:20:36 -07007700
Takashi Iwaia9111322011-05-02 11:30:18 +02007701static const struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702 { 8, NULL }
7703};
7704
Takashi Iwai49535502009-06-30 15:28:30 +02007705/* DACs */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007706static const hda_nid_t alc882_dac_nids[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707 /* front, rear, clfe, rear_surr */
7708 0x02, 0x03, 0x04, 0x05
7709};
Takashi Iwai49535502009-06-30 15:28:30 +02007710#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711
Takashi Iwai49535502009-06-30 15:28:30 +02007712/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007713#define alc882_adc_nids alc880_adc_nids
7714#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007715#define alc883_adc_nids alc882_adc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007716static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7717static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
Takashi Iwai49535502009-06-30 15:28:30 +02007718#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007719
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007720static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7721static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007722#define alc883_capsrc_nids alc882_capsrc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007723static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
Takashi Iwai49535502009-06-30 15:28:30 +02007724#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007725
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726/* input MUX */
7727/* FIXME: should be a matrix-type input source selection */
7728
Takashi Iwaia9111322011-05-02 11:30:18 +02007729static const struct hda_input_mux alc882_capture_source = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007730 .num_items = 4,
7731 .items = {
7732 { "Mic", 0x0 },
7733 { "Front Mic", 0x1 },
7734 { "Line", 0x2 },
7735 { "CD", 0x4 },
7736 },
7737};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007738
Takashi Iwai49535502009-06-30 15:28:30 +02007739#define alc883_capture_source alc882_capture_source
7740
Takashi Iwaia9111322011-05-02 11:30:18 +02007741static const struct hda_input_mux alc889_capture_source = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007742 .num_items = 3,
7743 .items = {
7744 { "Front Mic", 0x0 },
7745 { "Mic", 0x3 },
7746 { "Line", 0x2 },
7747 },
7748};
7749
Takashi Iwaia9111322011-05-02 11:30:18 +02007750static const struct hda_input_mux mb5_capture_source = {
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007751 .num_items = 3,
7752 .items = {
7753 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307754 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007755 { "CD", 0x4 },
7756 },
7757};
7758
Takashi Iwaia9111322011-05-02 11:30:18 +02007759static const struct hda_input_mux macmini3_capture_source = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007760 .num_items = 2,
7761 .items = {
7762 { "Line", 0x2 },
7763 { "CD", 0x4 },
7764 },
7765};
7766
Takashi Iwaia9111322011-05-02 11:30:18 +02007767static const struct hda_input_mux alc883_3stack_6ch_intel = {
Takashi Iwai49535502009-06-30 15:28:30 +02007768 .num_items = 4,
7769 .items = {
7770 { "Mic", 0x1 },
7771 { "Front Mic", 0x0 },
7772 { "Line", 0x2 },
7773 { "CD", 0x4 },
7774 },
7775};
7776
Takashi Iwaia9111322011-05-02 11:30:18 +02007777static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007778 .num_items = 2,
7779 .items = {
7780 { "Mic", 0x1 },
7781 { "Line", 0x2 },
7782 },
7783};
7784
Takashi Iwaia9111322011-05-02 11:30:18 +02007785static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007786 .num_items = 4,
7787 .items = {
7788 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007789 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007790 { "Line", 0x2 },
7791 { "CD", 0x4 },
7792 },
7793};
7794
Takashi Iwaia9111322011-05-02 11:30:18 +02007795static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007796 .num_items = 2,
7797 .items = {
7798 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007799 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007800 },
7801};
7802
Takashi Iwaia9111322011-05-02 11:30:18 +02007803static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007804 .num_items = 3,
7805 .items = {
7806 { "Mic", 0x0 },
7807 { "Front Mic", 0x1 },
7808 { "Line", 0x4 },
7809 },
7810};
7811
Takashi Iwaia9111322011-05-02 11:30:18 +02007812static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007813 .num_items = 2,
7814 .items = {
7815 { "Mic", 0x0 },
7816 { "Line", 0x2 },
7817 },
7818};
7819
Takashi Iwaia9111322011-05-02 11:30:18 +02007820static const struct hda_input_mux alc889A_mb31_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007821 .num_items = 2,
7822 .items = {
7823 { "Mic", 0x0 },
7824 /* Front Mic (0x01) unused */
7825 { "Line", 0x2 },
7826 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007827 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007828 },
7829};
7830
Takashi Iwaia9111322011-05-02 11:30:18 +02007831static const struct hda_input_mux alc889A_imac91_capture_source = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007832 .num_items = 2,
7833 .items = {
7834 { "Mic", 0x01 },
7835 { "Line", 0x2 }, /* Not sure! */
7836 },
7837};
7838
Takashi Iwai49535502009-06-30 15:28:30 +02007839/*
7840 * 2ch mode
7841 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007842static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007843 { 2, NULL }
7844};
7845
Kailang Yangdf694da2005-12-05 19:42:22 +01007846/*
Kailang Yang272a5272007-05-14 11:00:38 +02007847 * 2ch mode
7848 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007849static const struct hda_verb alc882_3ST_ch2_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007850 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7851 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7852 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7853 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7854 { } /* end */
7855};
7856
7857/*
Takashi Iwai49535502009-06-30 15:28:30 +02007858 * 4ch mode
7859 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007860static const struct hda_verb alc882_3ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007861 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7862 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7863 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7864 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7865 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7866 { } /* end */
7867};
7868
7869/*
Kailang Yang272a5272007-05-14 11:00:38 +02007870 * 6ch mode
7871 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007872static const struct hda_verb alc882_3ST_ch6_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007873 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7874 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7875 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7876 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7877 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7878 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7879 { } /* end */
7880};
7881
Takashi Iwaia9111322011-05-02 11:30:18 +02007882static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007883 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007884 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007885 { 6, alc882_3ST_ch6_init },
7886};
7887
Takashi Iwai49535502009-06-30 15:28:30 +02007888#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7889
Kailang Yang272a5272007-05-14 11:00:38 +02007890/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307891 * 2ch mode
7892 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007893static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307894 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7895 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7896 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7897 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7898 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7899 { } /* end */
7900};
7901
7902/*
7903 * 4ch mode
7904 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007905static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307906 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7907 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7908 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7909 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7910 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7911 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7912 { } /* end */
7913};
7914
7915/*
7916 * 6ch mode
7917 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007918static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307919 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7920 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7921 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7922 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7923 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7924 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7925 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7926 { } /* end */
7927};
7928
Takashi Iwaia9111322011-05-02 11:30:18 +02007929static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307930 { 2, alc883_3ST_ch2_clevo_init },
7931 { 4, alc883_3ST_ch4_clevo_init },
7932 { 6, alc883_3ST_ch6_clevo_init },
7933};
7934
7935
7936/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007937 * 6ch mode
7938 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007939static const struct hda_verb alc882_sixstack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007940 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7941 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7942 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7943 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7944 { } /* end */
7945};
7946
7947/*
7948 * 8ch mode
7949 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007950static const struct hda_verb alc882_sixstack_ch8_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007951 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7952 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7953 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7954 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7955 { } /* end */
7956};
7957
Takashi Iwaia9111322011-05-02 11:30:18 +02007958static const struct hda_channel_mode alc882_sixstack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007959 { 6, alc882_sixstack_ch6_init },
7960 { 8, alc882_sixstack_ch8_init },
7961};
7962
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007963
7964/* Macbook Air 2,1 */
7965
Takashi Iwaia9111322011-05-02 11:30:18 +02007966static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007967 { 2, NULL },
7968};
7969
Takashi Iwai87350ad2007-08-16 18:19:38 +02007970/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007971 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007972 */
7973
7974/*
7975 * 2ch mode
7976 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007977static const struct hda_verb alc885_mbp_ch2_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007978 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7979 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7980 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7981 { } /* end */
7982};
7983
7984/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007985 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007986 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007987static const struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007988 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7989 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7990 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7991 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7992 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7993 { } /* end */
7994};
7995
Takashi Iwaia9111322011-05-02 11:30:18 +02007996static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007997 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007998 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007999};
8000
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008001/*
8002 * 2ch
8003 * Speakers/Woofer/HP = Front
8004 * LineIn = Input
8005 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008006static const struct hda_verb alc885_mb5_ch2_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008007 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8008 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8009 { } /* end */
8010};
8011
8012/*
8013 * 6ch mode
8014 * Speakers/HP = Front
8015 * Woofer = LFE
8016 * LineIn = Surround
8017 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008018static const struct hda_verb alc885_mb5_ch6_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008019 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8020 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8021 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8022 { } /* end */
8023};
8024
Takashi Iwaia9111322011-05-02 11:30:18 +02008025static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008026 { 2, alc885_mb5_ch2_init },
8027 { 6, alc885_mb5_ch6_init },
8028};
Takashi Iwai87350ad2007-08-16 18:19:38 +02008029
Takashi Iwaid01aecd2010-02-23 08:07:15 +01008030#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02008031
8032/*
8033 * 2ch mode
8034 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008035static const struct hda_verb alc883_4ST_ch2_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008036 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8037 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8038 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8039 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8040 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8041 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8042 { } /* end */
8043};
8044
8045/*
8046 * 4ch mode
8047 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008048static const struct hda_verb alc883_4ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008049 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8050 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8051 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8052 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8053 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8054 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8055 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8056 { } /* end */
8057};
8058
8059/*
8060 * 6ch mode
8061 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008062static const struct hda_verb alc883_4ST_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008063 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8064 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8065 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8066 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8067 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
8068 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8069 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8070 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8071 { } /* end */
8072};
8073
8074/*
8075 * 8ch mode
8076 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008077static const struct hda_verb alc883_4ST_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008078 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8079 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8080 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8081 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8082 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8083 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
8084 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8085 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8086 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8087 { } /* end */
8088};
8089
Takashi Iwaia9111322011-05-02 11:30:18 +02008090static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008091 { 2, alc883_4ST_ch2_init },
8092 { 4, alc883_4ST_ch4_init },
8093 { 6, alc883_4ST_ch6_init },
8094 { 8, alc883_4ST_ch8_init },
8095};
8096
8097
8098/*
8099 * 2ch mode
8100 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008101static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008102 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8103 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8104 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8105 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8106 { } /* end */
8107};
8108
8109/*
8110 * 4ch mode
8111 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008112static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008113 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8114 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8115 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8116 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8117 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8118 { } /* end */
8119};
8120
8121/*
8122 * 6ch mode
8123 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008124static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008125 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8126 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8127 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
8128 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8129 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8130 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8131 { } /* end */
8132};
8133
Takashi Iwaia9111322011-05-02 11:30:18 +02008134static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008135 { 2, alc883_3ST_ch2_intel_init },
8136 { 4, alc883_3ST_ch4_intel_init },
8137 { 6, alc883_3ST_ch6_intel_init },
8138};
8139
8140/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008141 * 2ch mode
8142 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008143static const struct hda_verb alc889_ch2_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008144 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8145 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
8146 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
8147 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
8148 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8149 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8150 { } /* end */
8151};
8152
8153/*
Takashi Iwai49535502009-06-30 15:28:30 +02008154 * 6ch mode
8155 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008156static const struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008157 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8158 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
8159 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
8160 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8161 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008162 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8163 { } /* end */
8164};
8165
8166/*
8167 * 8ch mode
8168 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008169static const struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008170 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8171 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
8172 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
8173 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8174 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008175 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8176 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008177 { } /* end */
8178};
8179
Takashi Iwaia9111322011-05-02 11:30:18 +02008180static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008181 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008182 { 6, alc889_ch6_intel_init },
8183 { 8, alc889_ch8_intel_init },
8184};
8185
8186/*
8187 * 6ch mode
8188 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008189static const struct hda_verb alc883_sixstack_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008190 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
8191 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8192 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8193 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8194 { } /* end */
8195};
8196
8197/*
8198 * 8ch mode
8199 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008200static const struct hda_verb alc883_sixstack_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008201 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8202 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8203 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8204 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8205 { } /* end */
8206};
8207
Takashi Iwaia9111322011-05-02 11:30:18 +02008208static const struct hda_channel_mode alc883_sixstack_modes[2] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008209 { 6, alc883_sixstack_ch6_init },
8210 { 8, alc883_sixstack_ch8_init },
8211};
8212
8213
Linus Torvalds1da177e2005-04-16 15:20:36 -07008214/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
8215 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
8216 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008217static const struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02008218 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008219 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008220 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008221 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008222 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8223 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008224 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8225 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008226 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008227 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008228 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8229 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8230 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8231 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8232 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8233 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008234 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8236 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008237 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008239 { } /* end */
8240};
8241
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008242/* Macbook Air 2,1 same control for HP and internal Speaker */
8243
Takashi Iwaia9111322011-05-02 11:30:18 +02008244static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008245 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8246 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
8247 { }
8248};
8249
8250
Takashi Iwaia9111322011-05-02 11:30:18 +02008251static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008252 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8253 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
8254 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8255 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
8256 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008257 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8258 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008259 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8260 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008261 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8262 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008263 { } /* end */
8264};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008265
Takashi Iwaia9111322011-05-02 11:30:18 +02008266static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008267 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8268 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8269 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8270 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8271 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8272 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308273 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8274 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308275 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8276 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008277 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8278 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008279 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8280 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008281 { } /* end */
8282};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008283
Takashi Iwaia9111322011-05-02 11:30:18 +02008284static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008285 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8286 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8287 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8288 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8289 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8290 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8291 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8292 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8293 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8294 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008295 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008296 { } /* end */
8297};
8298
Takashi Iwaia9111322011-05-02 11:30:18 +02008299static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008300 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8301 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008302 { } /* end */
8303};
8304
8305
Takashi Iwaia9111322011-05-02 11:30:18 +02008306static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02008307 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8308 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8309 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8310 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8311 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8312 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8313 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008314 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008315 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008316 { } /* end */
8317};
8318
Takashi Iwaia9111322011-05-02 11:30:18 +02008319static const struct snd_kcontrol_new alc882_targa_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008320 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8321 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8322 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8323 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8324 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8325 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8326 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8327 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8328 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008329 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008330 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8331 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008332 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008333 { } /* end */
8334};
8335
8336/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8337 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8338 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008339static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008340 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8341 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8342 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8343 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8344 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8345 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8346 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8347 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8348 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8349 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8350 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8351 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008352 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008353 { } /* end */
8354};
8355
Takashi Iwaia9111322011-05-02 11:30:18 +02008356static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008357 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8358 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8359 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8360 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8361 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8362 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8363 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8364 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008365 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008366 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008367 { } /* end */
8368};
8369
Takashi Iwaia9111322011-05-02 11:30:18 +02008370static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008371 {
8372 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8373 .name = "Channel Mode",
8374 .info = alc_ch_mode_info,
8375 .get = alc_ch_mode_get,
8376 .put = alc_ch_mode_put,
8377 },
8378 { } /* end */
8379};
8380
Takashi Iwaia9111322011-05-02 11:30:18 +02008381static const struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008382 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008383 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8384 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008385 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008386 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8387 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008388 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008389 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8390 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008391 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008392 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8393 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008394
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008395 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008396 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008397 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008398 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008399 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008400 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008401 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008403 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008404 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008405 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008406 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008407 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008408 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008409 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008410 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008411 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008412 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008413 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8414 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008415 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008416 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8417 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008418 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008419 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8420 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8421 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8422 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8423 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008424 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008425 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008426
8427 /* FIXME: use matrix-type input source selection */
8428 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008429 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008430 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008431 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008432 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008433 /* ADC2: mute amp left and right */
8434 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008435 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008436 /* ADC3: mute amp left and right */
8437 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008438 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008439
8440 { }
8441};
8442
Takashi Iwaia9111322011-05-02 11:30:18 +02008443static const struct hda_verb alc882_adc1_init_verbs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008444 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8445 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8446 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8447 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8449 /* ADC1: mute amp left and right */
8450 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8451 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8452 { }
8453};
8454
Takashi Iwaia9111322011-05-02 11:30:18 +02008455static const struct hda_verb alc882_eapd_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008456 /* change to EAPD mode */
8457 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008458 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008459 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008460};
8461
Takashi Iwaia9111322011-05-02 11:30:18 +02008462static const struct hda_verb alc889_eapd_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008463 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8464 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8465 { }
8466};
8467
Takashi Iwaia9111322011-05-02 11:30:18 +02008468static const struct hda_verb alc_hp15_unsol_verbs[] = {
Wu Fengguang6732bd02009-07-30 09:19:14 +02008469 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8470 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8471 {}
8472};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008473
Takashi Iwaia9111322011-05-02 11:30:18 +02008474static const struct hda_verb alc885_init_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008475 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008476 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8477 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008478 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008479 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8480 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008481 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008482 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8483 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008484 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008485 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8486 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008487
8488 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008489 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008490 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8491 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8492 /* Front Pin: output 0 (0x0c) */
8493 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8494 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8495 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8496 /* Rear Pin: output 1 (0x0d) */
8497 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8498 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8499 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8500 /* CLFE Pin: output 2 (0x0e) */
8501 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8502 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8503 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8504 /* Side Pin: output 3 (0x0f) */
8505 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8506 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8507 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8508 /* Mic (rear) pin: input vref at 80% */
8509 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8510 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8511 /* Front Mic pin: input vref at 80% */
8512 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8513 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8514 /* Line In pin: input */
8515 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8516 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8517
8518 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8519 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008520 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008521 /* Input mixer2 */
8522 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008523 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008524 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008525 /* ADC2: mute amp left and right */
8526 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8527 /* ADC3: mute amp left and right */
8528 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8529
8530 { }
8531};
8532
Takashi Iwaia9111322011-05-02 11:30:18 +02008533static const struct hda_verb alc885_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008534 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8535 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8536 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8537 { }
8538};
8539
8540
8541/* Unmute Selector 24h and set the default input to front mic */
Takashi Iwaia9111322011-05-02 11:30:18 +02008542static const struct hda_verb alc889_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008543 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8544 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8545 { }
8546};
8547
8548
Takashi Iwai49535502009-06-30 15:28:30 +02008549#define alc883_init_verbs alc882_base_init_verbs
8550
Tobin Davis9102cd12006-12-15 10:02:12 +01008551/* Mac Pro test */
Takashi Iwaia9111322011-05-02 11:30:18 +02008552static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008553 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8554 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8555 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8556 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8557 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008558 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008559 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8560 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008561 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008562 { } /* end */
8563};
8564
Takashi Iwaia9111322011-05-02 11:30:18 +02008565static const struct hda_verb alc882_macpro_init_verbs[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008566 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8567 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8568 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8569 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8570 /* Front Pin: output 0 (0x0c) */
8571 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8572 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8573 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8574 /* Front Mic pin: input vref at 80% */
8575 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8576 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8577 /* Speaker: output */
8578 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8579 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8580 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8581 /* Headphone output (output 0 - 0x0c) */
8582 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8583 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8584 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8585
8586 /* FIXME: use matrix-type input source selection */
8587 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8588 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8589 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8590 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8591 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8592 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8593 /* Input mixer2 */
8594 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8595 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8596 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8597 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8598 /* Input mixer3 */
8599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8600 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8601 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8602 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8603 /* ADC1: mute amp left and right */
8604 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8605 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8606 /* ADC2: mute amp left and right */
8607 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8608 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8609 /* ADC3: mute amp left and right */
8610 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8611 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8612
8613 { }
8614};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008615
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008616/* Macbook 5,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008617static const struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008618 /* DACs */
8619 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8620 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8621 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8622 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008623 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008624 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8625 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8626 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008627 /* Surround mixer */
8628 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8629 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8630 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8631 /* LFE mixer */
8632 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8633 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8634 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8635 /* HP mixer */
8636 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8637 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8638 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8639 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008640 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8641 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008642 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8643 /* LFE Pin (0x0e) */
8644 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8645 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8646 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8647 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008648 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8649 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008650 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308651 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008652 /* Front Mic pin: input vref at 80% */
8653 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8654 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8655 /* Line In pin */
8656 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8657 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8658
Alex Murrayb8f171e2010-06-14 12:08:43 +09308659 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8660 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8661 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008662 { }
8663};
8664
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008665/* Macmini 3,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008666static const struct hda_verb alc885_macmini3_init_verbs[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008667 /* DACs */
8668 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8669 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8670 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8671 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8672 /* Front mixer */
8673 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8674 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8675 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8676 /* Surround mixer */
8677 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8678 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8679 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8680 /* LFE mixer */
8681 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8682 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8683 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8684 /* HP mixer */
8685 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8686 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8687 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8688 /* Front Pin (0x0c) */
8689 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8690 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8691 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8692 /* LFE Pin (0x0e) */
8693 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8694 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8695 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8696 /* HP Pin (0x0f) */
8697 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8698 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8699 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8700 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8701 /* Line In pin */
8702 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8703 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8704
8705 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8706 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8707 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8708 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8709 { }
8710};
8711
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008712
Takashi Iwaia9111322011-05-02 11:30:18 +02008713static const struct hda_verb alc885_mba21_init_verbs[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008714 /*Internal and HP Speaker Mixer*/
8715 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8716 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8717 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8718 /*Internal Speaker Pin (0x0c)*/
8719 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8720 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8721 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8722 /* HP Pin: output 0 (0x0e) */
8723 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8724 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8725 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8726 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8727 /* Line in (is hp when jack connected)*/
8728 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8729 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8730
8731 { }
8732 };
8733
8734
Takashi Iwai87350ad2007-08-16 18:19:38 +02008735/* Macbook Pro rev3 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008736static const struct hda_verb alc885_mbp3_init_verbs[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02008737 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8738 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8739 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8740 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8741 /* Rear mixer */
8742 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8743 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8744 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008745 /* HP mixer */
8746 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8747 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8748 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008749 /* Front Pin: output 0 (0x0c) */
8750 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8751 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8752 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008753 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008754 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008755 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8756 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008757 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8758 /* Mic (rear) pin: input vref at 80% */
8759 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8760 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8761 /* Front Mic pin: input vref at 80% */
8762 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8763 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8764 /* Line In pin: use output 1 when in LineOut mode */
8765 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8766 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8767 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8768
8769 /* FIXME: use matrix-type input source selection */
8770 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8771 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8772 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8773 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8774 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8775 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8776 /* Input mixer2 */
8777 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8778 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8779 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8780 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8781 /* Input mixer3 */
8782 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8783 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8784 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8785 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8786 /* ADC1: mute amp left and right */
8787 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8788 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8789 /* ADC2: mute amp left and right */
8790 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8791 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8792 /* ADC3: mute amp left and right */
8793 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8794 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8795
8796 { }
8797};
8798
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008799/* iMac 9,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008800static const struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008801 /* Internal Speaker Pin (0x0c) */
8802 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8803 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8804 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8805 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8806 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8807 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8808 /* HP Pin: Rear */
8809 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8810 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8811 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8812 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8813 /* Line in Rear */
8814 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8815 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8816 /* Front Mic pin: input vref at 80% */
8817 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8818 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008819 /* Rear mixer */
8820 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8821 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8822 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008823 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8824 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8825 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8826 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8827 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008828 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8829 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8830 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8831 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008832 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008833 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8834 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8835 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8836 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008837 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008838 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8839 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8840 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8841 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008842 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008843 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8844 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008845 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8847 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008848 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008849 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8850 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008851 { }
8852};
8853
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008854/* iMac 24 mixer. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008855static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008856 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8857 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8858 { } /* end */
8859};
8860
8861/* iMac 24 init verbs. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008862static const struct hda_verb alc885_imac24_init_verbs[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008863 /* Internal speakers: output 0 (0x0c) */
8864 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8865 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8866 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8867 /* Internal speakers: output 0 (0x0c) */
8868 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8869 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8870 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8871 /* Headphone: output 0 (0x0c) */
8872 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8873 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8874 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8875 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8876 /* Front Mic: input vref at 80% */
8877 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8878 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8879 { }
8880};
8881
8882/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008883static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008884{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008885 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008886
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008887 spec->autocfg.hp_pins[0] = 0x14;
8888 spec->autocfg.speaker_pins[0] = 0x18;
8889 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008890 spec->automute = 1;
8891 spec->automute_mode = ALC_AUTOMUTE_AMP;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008892}
8893
Takashi Iwai9d54f082010-02-22 08:34:40 +01008894#define alc885_mb5_setup alc885_imac24_setup
8895#define alc885_macmini3_setup alc885_imac24_setup
8896
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008897/* Macbook Air 2,1 */
8898static void alc885_mba21_setup(struct hda_codec *codec)
8899{
8900 struct alc_spec *spec = codec->spec;
8901
8902 spec->autocfg.hp_pins[0] = 0x14;
8903 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02008904 spec->automute = 1;
8905 spec->automute_mode = ALC_AUTOMUTE_AMP;
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008906}
8907
8908
8909
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008910static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008911{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008912 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008913
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008914 spec->autocfg.hp_pins[0] = 0x15;
8915 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02008916 spec->automute = 1;
8917 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008918}
8919
Takashi Iwai9d54f082010-02-22 08:34:40 +01008920static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308921{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008922 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308923
Takashi Iwai9d54f082010-02-22 08:34:40 +01008924 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008925 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008926 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008927 spec->automute = 1;
8928 spec->automute_mode = ALC_AUTOMUTE_AMP;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008929}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008930
Takashi Iwaia9111322011-05-02 11:30:18 +02008931static const struct hda_verb alc882_targa_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8933 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8934
8935 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8936 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008937
Kailang Yang272a5272007-05-14 11:00:38 +02008938 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8939 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8940 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8941
8942 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008943 { } /* end */
8944};
8945
8946/* toggle speaker-output according to the hp-jack state */
8947static void alc882_targa_automute(struct hda_codec *codec)
8948{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008949 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02008950 alc_hp_automute(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008951 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008952 spec->jack_present ? 1 : 3);
8953}
8954
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008955static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008956{
8957 struct alc_spec *spec = codec->spec;
8958
8959 spec->autocfg.hp_pins[0] = 0x14;
8960 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02008961 spec->automute = 1;
8962 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02008963}
8964
8965static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8966{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008967 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008968 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008969}
8970
Takashi Iwaia9111322011-05-02 11:30:18 +02008971static const struct hda_verb alc882_asus_a7j_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008972 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8973 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8974
8975 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8976 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8977 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008978
Kailang Yang272a5272007-05-14 11:00:38 +02008979 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8980 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8981 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8982
8983 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8984 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8985 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8986 { } /* end */
8987};
8988
Takashi Iwaia9111322011-05-02 11:30:18 +02008989static const struct hda_verb alc882_asus_a7m_verbs[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008990 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8991 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8992
8993 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8994 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8995 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008996
Takashi Iwai914759b2007-09-06 14:52:04 +02008997 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8998 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8999 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
9000
9001 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
9002 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
9003 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
9004 { } /* end */
9005};
9006
Tobin Davis9102cd12006-12-15 10:02:12 +01009007static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
9008{
9009 unsigned int gpiostate, gpiomask, gpiodir;
9010
9011 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
9012 AC_VERB_GET_GPIO_DATA, 0);
9013
9014 if (!muted)
9015 gpiostate |= (1 << pin);
9016 else
9017 gpiostate &= ~(1 << pin);
9018
9019 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
9020 AC_VERB_GET_GPIO_MASK, 0);
9021 gpiomask |= (1 << pin);
9022
9023 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
9024 AC_VERB_GET_GPIO_DIRECTION, 0);
9025 gpiodir |= (1 << pin);
9026
9027
9028 snd_hda_codec_write(codec, codec->afg, 0,
9029 AC_VERB_SET_GPIO_MASK, gpiomask);
9030 snd_hda_codec_write(codec, codec->afg, 0,
9031 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
9032
9033 msleep(1);
9034
9035 snd_hda_codec_write(codec, codec->afg, 0,
9036 AC_VERB_SET_GPIO_DATA, gpiostate);
9037}
9038
Takashi Iwai7debbe52007-08-16 15:01:03 +02009039/* set up GPIO at initialization */
9040static void alc885_macpro_init_hook(struct hda_codec *codec)
9041{
9042 alc882_gpio_mute(codec, 0, 0);
9043 alc882_gpio_mute(codec, 1, 0);
9044}
9045
9046/* set up GPIO and update auto-muting at initialization */
9047static void alc885_imac24_init_hook(struct hda_codec *codec)
9048{
9049 alc885_macpro_init_hook(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02009050 alc_hp_automute(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02009051}
9052
Kailang Yangdf694da2005-12-05 19:42:22 +01009053/*
9054 * generic initialization of ADC, input mixers and output mixers
9055 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009056static const struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01009057 /*
9058 * Unmute ADC0-2 and set the default input to mic-in
9059 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009060 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9061 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9062 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9063 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9064
Kailang Yangdf694da2005-12-05 19:42:22 +01009065 /*
9066 * Set up output mixers (0x0c - 0x0f)
9067 */
9068 /* set vol=0 to output mixers */
9069 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9070 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9071 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9072 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9073 /* set up input amps for analog loopback */
9074 /* Amp Indices: DAC = 0, mixer = 1 */
9075 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9076 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9077 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9078 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9079 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9080 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9081 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9082 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9083 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9084 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9085
9086 /* FIXME: use matrix-type input source selection */
9087 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01009088 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01009089 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009090 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01009091 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009092 { }
9093};
9094
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009095/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009096static const struct hda_verb alc889A_mb31_ch2_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009097 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
9098 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
9099 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
9100 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
9101 { } /* end */
9102};
9103
9104/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009105static const struct hda_verb alc889A_mb31_ch4_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009106 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
9107 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
9108 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
9109 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
9110 { } /* end */
9111};
9112
9113/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009114static const struct hda_verb alc889A_mb31_ch5_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009115 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
9116 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
9117 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
9118 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
9119 { } /* end */
9120};
9121
9122/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009123static const struct hda_verb alc889A_mb31_ch6_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009124 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
9125 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
9126 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
9127 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
9128 { } /* end */
9129};
9130
Takashi Iwaia9111322011-05-02 11:30:18 +02009131static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009132 { 2, alc889A_mb31_ch2_init },
9133 { 4, alc889A_mb31_ch4_init },
9134 { 5, alc889A_mb31_ch5_init },
9135 { 6, alc889A_mb31_ch6_init },
9136};
9137
Takashi Iwaia9111322011-05-02 11:30:18 +02009138static const struct hda_verb alc883_medion_eapd_verbs[] = {
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009139 /* eanable EAPD on medion laptop */
9140 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9141 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9142 { }
9143};
9144
Takashi Iwai49535502009-06-30 15:28:30 +02009145#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009146
Takashi Iwaia9111322011-05-02 11:30:18 +02009147static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009148 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9149 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9150 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9151 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9152 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9153 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9154 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9155 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009156 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009157 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9158 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009159 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009160 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009161 { } /* end */
9162};
9163
Takashi Iwaia9111322011-05-02 11:30:18 +02009164static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009165 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9166 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
9167 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9168 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
9169 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009170 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01009171 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009172 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009173 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009174 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01009175 { } /* end */
9176};
9177
Takashi Iwaia9111322011-05-02 11:30:18 +02009178static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009179 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9180 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
9181 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9182 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
9183 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009184 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01009185 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009186 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009187 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009188 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01009189 { } /* end */
9190};
9191
Takashi Iwaia9111322011-05-02 11:30:18 +02009192static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009193 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9194 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9195 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9196 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9197 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9198 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9199 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9200 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009201 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009202 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9203 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009204 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009205 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009206 { } /* end */
9207};
9208
Takashi Iwaia9111322011-05-02 11:30:18 +02009209static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009210 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9211 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9212 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9213 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9214 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9215 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9216 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9217 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9218 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9219 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9220 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9221 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9222 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9223 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009224 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009225 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9226 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009227 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009228 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009229 { } /* end */
9230};
9231
Takashi Iwaia9111322011-05-02 11:30:18 +02009232static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
Jiang zhe17bba1b2008-06-04 12:11:07 +02009233 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9234 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9235 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9236 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9237 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9238 HDA_OUTPUT),
9239 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9240 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9241 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9242 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9243 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9244 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9245 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9246 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9247 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009248 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009249 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9250 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009251 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009252 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009253 { } /* end */
9254};
9255
Takashi Iwaia9111322011-05-02 11:30:18 +02009256static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009257 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9258 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9259 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9260 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9261 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9262 HDA_OUTPUT),
9263 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9264 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9265 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9266 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9267 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9268 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9269 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9270 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009272 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009273 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9274 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009275 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009276 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9277 { } /* end */
9278};
9279
Takashi Iwaia9111322011-05-02 11:30:18 +02009280static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009281 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009282 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009283 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009284 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009285 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9286 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009287 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9288 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009289 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9290 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9291 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9292 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9293 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009295 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009296 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9297 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009298 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009299 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009300 { } /* end */
9301};
9302
Takashi Iwaia9111322011-05-02 11:30:18 +02009303static const struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009304 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009305 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009306 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009307 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009308 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9309 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9310 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9311 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9312 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9313 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9314 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9315 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9316 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9317 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9318 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009319 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009320 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009321 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009322};
Kailang Yangccc656c2006-10-17 12:32:26 +02009323
Takashi Iwaia9111322011-05-02 11:30:18 +02009324static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009325 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009326 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009327 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009328 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009329 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9330 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9331 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009332 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009333 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009334 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009335 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009336 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009337 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009338};
Kailang Yangccc656c2006-10-17 12:32:26 +02009339
Takashi Iwaia9111322011-05-02 11:30:18 +02009340static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009341 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9342 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009343 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009344 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009345 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009346 { } /* end */
9347};
9348
Takashi Iwaia9111322011-05-02 11:30:18 +02009349static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009350 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9351 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009352 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9353 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009354 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9355 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009356 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009357 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009358 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009359};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009360
Takashi Iwaia9111322011-05-02 11:30:18 +02009361static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009362 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9363 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9364 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9365 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9366 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9367 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9368 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009369 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9370 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009371 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009372};
Kailang Yang272a5272007-05-14 11:00:38 +02009373
Takashi Iwaia9111322011-05-02 11:30:18 +02009374static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009375 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9376 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9377 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9378 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9379 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9380 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9381 { } /* end */
9382};
9383
Takashi Iwaia9111322011-05-02 11:30:18 +02009384static const struct hda_verb alc883_medion_wim2160_verbs[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009385 /* Unmute front mixer */
9386 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9387 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9388
9389 /* Set speaker pin to front mixer */
9390 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9391
9392 /* Init headphone pin */
9393 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9394 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9395 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9396 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9397
9398 { } /* end */
9399};
9400
9401/* toggle speaker-output according to the hp-jack state */
9402static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9403{
9404 struct alc_spec *spec = codec->spec;
9405
9406 spec->autocfg.hp_pins[0] = 0x1a;
9407 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009408 spec->automute = 1;
9409 spec->automute_mode = ALC_AUTOMUTE_AMP;
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009410}
9411
Takashi Iwaia9111322011-05-02 11:30:18 +02009412static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009413 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9414 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009415 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009416 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9417 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009418 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009419 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009420 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009421 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009422};
Tobin Davis2880a862007-08-07 11:50:26 +02009423
Takashi Iwaia9111322011-05-02 11:30:18 +02009424static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01009425 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009426 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009427 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9428 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009429 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9430 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9431 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009432 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009433 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9434 { } /* end */
9435};
9436
Takashi Iwaia9111322011-05-02 11:30:18 +02009437static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009438 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9439 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9440 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9441 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9442 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9443 0x0d, 1, 0x0, HDA_OUTPUT),
9444 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9445 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9446 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9447 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9448 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009449 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9450 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9451 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9452 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9453 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009454 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009455 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9456 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009457 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009458 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009459 { } /* end */
9460};
9461
Takashi Iwaia9111322011-05-02 11:30:18 +02009462static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009463 /* Output mixers */
9464 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9465 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9466 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9467 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9468 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9469 HDA_OUTPUT),
9470 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9471 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9472 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9473 /* Output switches */
9474 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9475 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9476 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9477 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009478 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9479 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009480 /* Input mixers */
9481 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9482 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9483 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9484 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9485 { } /* end */
9486};
9487
Takashi Iwaia9111322011-05-02 11:30:18 +02009488static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009489 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9490 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9491 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9492 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009493 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c2009-06-05 00:47:26 +02009494 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9495 { } /* end */
9496};
9497
Takashi Iwaia9111322011-05-02 11:30:18 +02009498static const struct hda_bind_ctls alc883_bind_cap_vol = {
Kailang Yange2757d52008-08-26 13:17:46 +02009499 .ops = &snd_hda_bind_vol,
9500 .values = {
9501 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9502 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9503 0
9504 },
9505};
9506
Takashi Iwaia9111322011-05-02 11:30:18 +02009507static const struct hda_bind_ctls alc883_bind_cap_switch = {
Kailang Yange2757d52008-08-26 13:17:46 +02009508 .ops = &snd_hda_bind_sw,
9509 .values = {
9510 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9511 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9512 0
9513 },
9514};
9515
Takashi Iwaia9111322011-05-02 11:30:18 +02009516static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009517 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9518 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9519 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9520 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9521 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9522 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009523 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009524 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009525 { } /* end */
9526};
9527
Takashi Iwaia9111322011-05-02 11:30:18 +02009528static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009529 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9530 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9531 {
9532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9533 /* .name = "Capture Source", */
9534 .name = "Input Source",
9535 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009536 .info = alc_mux_enum_info,
9537 .get = alc_mux_enum_get,
9538 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009539 },
9540 { } /* end */
9541};
9542
Takashi Iwaia9111322011-05-02 11:30:18 +02009543static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009544 {
9545 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9546 .name = "Channel Mode",
9547 .info = alc_ch_mode_info,
9548 .get = alc_ch_mode_get,
9549 .put = alc_ch_mode_put,
9550 },
9551 { } /* end */
9552};
9553
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009554/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009555static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009556{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009557 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009558
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009559 spec->autocfg.hp_pins[0] = 0x15;
9560 spec->autocfg.speaker_pins[0] = 0x14;
9561 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009562 spec->automute = 1;
9563 spec->automute_mode = ALC_AUTOMUTE_AMP;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009564}
9565
Takashi Iwaia9111322011-05-02 11:30:18 +02009566static const struct hda_verb alc883_mitac_verbs[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009567 /* HP */
9568 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9569 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9570 /* Subwoofer */
9571 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9572 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9573
9574 /* enable unsolicited event */
9575 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9576 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9577
9578 { } /* end */
9579};
9580
Takashi Iwaia9111322011-05-02 11:30:18 +02009581static const struct hda_verb alc883_clevo_m540r_verbs[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309582 /* HP */
9583 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9584 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9585 /* Int speaker */
9586 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9587
9588 /* enable unsolicited event */
9589 /*
9590 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9591 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9592 */
9593
9594 { } /* end */
9595};
9596
Takashi Iwaia9111322011-05-02 11:30:18 +02009597static const struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009598 /* HP */
9599 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9600 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9601 /* Int speaker */
9602 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9603 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9604
9605 /* enable unsolicited event */
9606 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009607 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009608
9609 { } /* end */
9610};
9611
Takashi Iwaia9111322011-05-02 11:30:18 +02009612static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009613 /* HP */
9614 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9615 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9616 /* Subwoofer */
9617 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9618 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9619
9620 /* enable unsolicited event */
9621 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9622
9623 { } /* end */
9624};
9625
Takashi Iwaia9111322011-05-02 11:30:18 +02009626static const struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009627 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9628 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9629
9630 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9631 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009632
David Heidelberger64a8be72009-06-08 16:15:18 +02009633/* Connect Line-Out side jack (SPDIF) to Side */
9634 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9635 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9636 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9637/* Connect Mic jack to CLFE */
9638 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9639 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9640 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9641/* Connect Line-in jack to Surround */
9642 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9643 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9644 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9645/* Connect HP out jack to Front */
9646 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9647 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9648 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009649
9650 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009651
9652 { } /* end */
9653};
9654
Takashi Iwaia9111322011-05-02 11:30:18 +02009655static const struct hda_verb alc883_lenovo_101e_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009656 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9657 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9658 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9659 { } /* end */
9660};
9661
Takashi Iwaia9111322011-05-02 11:30:18 +02009662static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009663 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9664 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9665 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9666 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9667 { } /* end */
9668};
9669
Takashi Iwaia9111322011-05-02 11:30:18 +02009670static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009671 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9672 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9673 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9674 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9675 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9676 { } /* end */
9677};
9678
Takashi Iwaia9111322011-05-02 11:30:18 +02009679static const struct hda_verb alc883_haier_w66_verbs[] = {
Kailang Yang189609a2007-08-20 11:31:23 +02009680 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9681 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9682
9683 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9684
9685 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9686 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9687 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9688 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9689 { } /* end */
9690};
9691
Takashi Iwaia9111322011-05-02 11:30:18 +02009692static const struct hda_verb alc888_lenovo_sky_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009693 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9694 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9695 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9696 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9697 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9698 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9699 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9700 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9701 { } /* end */
9702};
9703
Takashi Iwaia9111322011-05-02 11:30:18 +02009704static const struct hda_verb alc888_6st_dell_verbs[] = {
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009705 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9706 { }
9707};
9708
Takashi Iwaia9111322011-05-02 11:30:18 +02009709static const struct hda_verb alc883_vaiott_verbs[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009710 /* HP */
9711 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9712 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9713
9714 /* enable unsolicited event */
9715 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9716
9717 { } /* end */
9718};
9719
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009720static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009721{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009722 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009723
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009724 spec->autocfg.hp_pins[0] = 0x1b;
9725 spec->autocfg.speaker_pins[0] = 0x14;
9726 spec->autocfg.speaker_pins[1] = 0x16;
9727 spec->autocfg.speaker_pins[2] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02009728 spec->automute = 1;
9729 spec->automute_mode = ALC_AUTOMUTE_AMP;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009730}
9731
Takashi Iwaia9111322011-05-02 11:30:18 +02009732static const struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009733 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009734 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9735 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009736 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009737 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009738};
9739
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009740/*
9741 * 2ch mode
9742 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009743static const struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009744 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9745 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9746 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9747 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009748 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009749};
9750
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009751/*
9752 * 4ch mode
9753 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009754static const struct hda_verb alc888_3st_hp_4ch_init[] = {
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009755 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9756 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9757 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9758 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9759 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9760 { } /* end */
9761};
9762
9763/*
9764 * 6ch mode
9765 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009766static const struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009767 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9768 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009769 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009770 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9771 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009772 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9773 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009774};
9775
Takashi Iwaia9111322011-05-02 11:30:18 +02009776static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009777 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009778 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009779 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009780};
9781
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009782static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009783{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009784 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009785
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009786 spec->autocfg.hp_pins[0] = 0x1b;
9787 spec->autocfg.line_out_pins[0] = 0x14;
9788 spec->autocfg.speaker_pins[0] = 0x15;
9789 spec->automute = 1;
9790 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009791}
9792
Kailang Yang272a5272007-05-14 11:00:38 +02009793/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc427172010-11-29 07:42:59 +01009794static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009795{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009796 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009797
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009798 spec->autocfg.hp_pins[0] = 0x14;
9799 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009800 spec->automute = 1;
9801 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009802}
9803
Kailang Yangccc656c2006-10-17 12:32:26 +02009804/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009805#define alc883_targa_init_hook alc882_targa_init_hook
9806#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009807
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009808static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009809{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009810 struct alc_spec *spec = codec->spec;
9811
9812 spec->autocfg.hp_pins[0] = 0x15;
9813 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009814 spec->automute = 1;
9815 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009816}
9817
9818static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9819{
Takashi Iwaid922b512011-04-28 12:18:53 +02009820 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009821 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009822}
9823
9824static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009825 unsigned int res)
9826{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009827 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009828 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009829 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009830 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009831 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02009832 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009833 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009834 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009835}
9836
Jiang zhefb97dc62008-03-06 11:07:11 +01009837/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009838static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009839{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009840 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009841
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009842 spec->autocfg.hp_pins[0] = 0x14;
9843 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009844 spec->automute = 1;
9845 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhefb97dc62008-03-06 11:07:11 +01009846}
9847
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009848static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009849{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009850 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009851
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009852 spec->autocfg.hp_pins[0] = 0x1b;
9853 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009854 spec->automute = 1;
9855 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang189609a2007-08-20 11:31:23 +02009856}
9857
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009858static void alc883_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009859{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009860 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009861
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009862 spec->autocfg.hp_pins[0] = 0x1b;
9863 spec->autocfg.line_out_pins[0] = 0x14;
9864 spec->autocfg.speaker_pins[0] = 0x15;
9865 spec->automute = 1;
9866 spec->detect_line = 1;
9867 spec->automute_lines = 1;
9868 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009869}
9870
Takashi Iwai676a9b52007-08-16 15:23:35 +02009871/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009872static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009873{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009874 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009875
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009876 spec->autocfg.hp_pins[0] = 0x14;
9877 spec->autocfg.speaker_pins[0] = 0x15;
9878 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02009879 spec->automute = 1;
9880 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009881}
9882
Takashi Iwaia9111322011-05-02 11:30:18 +02009883static const struct hda_verb alc883_acer_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009884 /* HP Pin: output 0 (0x0c) */
9885 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9886 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9887 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9888 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009889 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9890 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009891 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009892 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9893 /* eanable EAPD on medion laptop */
9894 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9895 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009896 /* enable unsolicited event */
9897 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009898 { }
9899};
9900
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009901static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009902{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009903 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009904
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009905 spec->autocfg.hp_pins[0] = 0x1b;
9906 spec->autocfg.speaker_pins[0] = 0x14;
9907 spec->autocfg.speaker_pins[1] = 0x15;
9908 spec->autocfg.speaker_pins[2] = 0x16;
9909 spec->autocfg.speaker_pins[3] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009910 spec->automute = 1;
9911 spec->automute_mode = ALC_AUTOMUTE_AMP;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009912}
9913
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009914static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009915{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009916 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009917
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009918 spec->autocfg.hp_pins[0] = 0x1b;
9919 spec->autocfg.speaker_pins[0] = 0x14;
9920 spec->autocfg.speaker_pins[1] = 0x15;
9921 spec->autocfg.speaker_pins[2] = 0x16;
9922 spec->autocfg.speaker_pins[3] = 0x17;
9923 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02009924 spec->automute = 1;
9925 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009926}
9927
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009928static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009929{
9930 struct alc_spec *spec = codec->spec;
9931
9932 spec->autocfg.hp_pins[0] = 0x15;
9933 spec->autocfg.speaker_pins[0] = 0x14;
9934 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009935 spec->automute = 1;
9936 spec->automute_mode = ALC_AUTOMUTE_AMP;
Guido Günther3e1647c2009-06-05 00:47:26 +02009937}
9938
Takashi Iwaia9111322011-05-02 11:30:18 +02009939static const struct hda_verb alc888_asus_m90v_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009940 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9941 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9942 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9943 /* enable unsolicited event */
9944 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9945 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9946 { } /* end */
9947};
9948
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009949static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009950{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009951 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009952
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009953 spec->autocfg.hp_pins[0] = 0x1b;
9954 spec->autocfg.speaker_pins[0] = 0x14;
9955 spec->autocfg.speaker_pins[1] = 0x15;
9956 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009957 spec->ext_mic.pin = 0x18;
9958 spec->int_mic.pin = 0x19;
9959 spec->ext_mic.mux_idx = 0;
9960 spec->int_mic.mux_idx = 1;
9961 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +02009962 spec->automute = 1;
9963 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009964}
9965
Takashi Iwaia9111322011-05-02 11:30:18 +02009966static const struct hda_verb alc888_asus_eee1601_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009967 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9968 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9969 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9970 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9971 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9972 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9973 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9974 /* enable unsolicited event */
9975 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9976 { } /* end */
9977};
9978
Kailang Yange2757d52008-08-26 13:17:46 +02009979static void alc883_eee1601_inithook(struct hda_codec *codec)
9980{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009981 struct alc_spec *spec = codec->spec;
9982
9983 spec->autocfg.hp_pins[0] = 0x14;
9984 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02009985 alc_hp_automute(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009986}
9987
Takashi Iwaia9111322011-05-02 11:30:18 +02009988static const struct hda_verb alc889A_mb31_verbs[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009989 /* Init rear pin (used as headphone output) */
9990 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9991 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9992 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9993 /* Init line pin (used as output in 4ch and 6ch mode) */
9994 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9995 /* Init line 2 pin (used as headphone out by default) */
9996 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9997 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9998 { } /* end */
9999};
10000
10001/* Mute speakers according to the headphone jack state */
10002static void alc889A_mb31_automute(struct hda_codec *codec)
10003{
10004 unsigned int present;
10005
10006 /* Mute only in 2ch or 4ch mode */
10007 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
10008 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010009 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010010 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10011 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
10012 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10013 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
10014 }
10015}
10016
10017static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
10018{
10019 if ((res >> 26) == ALC880_HP_EVENT)
10020 alc889A_mb31_automute(codec);
10021}
10022
Takashi Iwai49535502009-06-30 15:28:30 +020010023
Takashi Iwaicb53c622007-08-10 17:21:45 +020010024#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +020010025#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +020010026#endif
10027
Sasha Alexandrdef319f2009-06-16 16:00:15 -040010028/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +020010029#define alc882_pcm_analog_playback alc880_pcm_analog_playback
10030#define alc882_pcm_analog_capture alc880_pcm_analog_capture
10031#define alc882_pcm_digital_playback alc880_pcm_digital_playback
10032#define alc882_pcm_digital_capture alc880_pcm_digital_capture
10033
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020010034static const hda_nid_t alc883_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010035 ALC1200_DIGOUT_NID, 0,
10036};
10037
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020010038static const hda_nid_t alc1200_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010039 ALC883_DIGOUT_NID, 0,
10040};
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010041
10042/*
10043 * configuration and preset
10044 */
Takashi Iwaiea734962011-01-17 11:29:34 +010010045static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010046 [ALC882_3ST_DIG] = "3stack-dig",
10047 [ALC882_6ST_DIG] = "6stack-dig",
10048 [ALC882_ARIMA] = "arima",
10049 [ALC882_W2JC] = "w2jc",
10050 [ALC882_TARGA] = "targa",
10051 [ALC882_ASUS_A7J] = "asus-a7j",
10052 [ALC882_ASUS_A7M] = "asus-a7m",
10053 [ALC885_MACPRO] = "macpro",
10054 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010055 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010056 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +020010057 [ALC885_MBP3] = "mbp3",
10058 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010059 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +020010060 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010061 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
10062 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +020010063 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010064 [ALC883_TARGA_DIG] = "targa-dig",
10065 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +020010066 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010067 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +020010068 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010069 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +020010070 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +020010071 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010072 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010073 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010074 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010075 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010076 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +020010077 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
10078 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +020010079 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +020010080 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010081 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010082 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010083 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010084 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010085 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +010010086 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010087 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +020010088 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010089 [ALC889A_INTEL] = "intel-alc889a",
10090 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +010010091 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010092 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +020010093 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +020010094 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010095};
10096
Takashi Iwaia9111322011-05-02 11:30:18 +020010097static const struct snd_pci_quirk alc882_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010098 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
10099
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010100 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +010010101 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +010010102 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010103 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
10104 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +020010105 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010106 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
10107 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +010010108 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +010010109 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +020010110 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
10111 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +020010112 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
10113 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +020010114 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
10115 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +010010116 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +020010117 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +010010118 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +010010119 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010120 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
10121 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +020010122 /* default Acer -- disabled as it causes more problems.
10123 * model=auto should work fine now
10124 */
10125 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +020010126
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010127 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +020010128
Lucas De Marchi25985ed2011-03-30 22:57:33 -030010129 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010130 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
10131 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +010010132 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +010010133 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -030010134 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +020010135
10136 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
10137 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
10138 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +020010139 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +020010140 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
10141 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
10142 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010143 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +010010144 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +010010145 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +020010146 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +020010147
10148 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +020010149 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010150 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +110010151 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010152 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
10153 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +020010154 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010155 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwaiebb47242011-05-02 10:37:29 +020010156 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010157
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010158 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
10159 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
10160 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010161 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +010010162 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +020010163 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010164 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +010010165 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010166 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
10167 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
10168 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
10169 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
10170 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
10171 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -070010172 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010173 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
10174 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
10175 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +010010176 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +020010177 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010178 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
10179 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +020010180 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +010010181 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +010010182 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +010010183 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +020010184 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -040010185 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +010010186 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010187 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -070010188 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010189
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010190 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +020010191 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010192 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
10193 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010194 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010195 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -040010196 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +020010197 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010198 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +020010199 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +010010200 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +020010201 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010202 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +020010203 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +020010204 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010205 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
10206 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +020010207 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +010010208 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +010010209 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +020010210 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +020010211
Jiang zhe17bba1b2008-06-04 12:11:07 +020010212 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
10213 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +110010214 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010215 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
10216 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
10217 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -040010218 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010219
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010220 {}
10221};
10222
Takashi Iwai49535502009-06-30 15:28:30 +020010223/* codec SSID table for Intel Mac */
Takashi Iwaia9111322011-05-02 11:30:18 +020010224static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010225 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
10226 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
10227 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
10228 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
10229 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
10230 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
10231 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -040010232 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -070010233 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -070010234 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -070010235 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +020010236 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
10237 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
10238 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010239 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +020010240 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +100010241 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010242 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
10243 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +020010244 */
10245 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010246 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010247 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +020010248 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010249};
10250
Takashi Iwaia9111322011-05-02 11:30:18 +020010251static const struct alc_config_preset alc882_presets[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010252 [ALC882_3ST_DIG] = {
10253 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010254 .init_verbs = { alc882_base_init_verbs,
10255 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010256 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10257 .dac_nids = alc882_dac_nids,
10258 .dig_out_nid = ALC882_DIGOUT_NID,
10259 .dig_in_nid = ALC882_DIGIN_NID,
10260 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10261 .channel_mode = alc882_ch_modes,
10262 .need_dac_fix = 1,
10263 .input_mux = &alc882_capture_source,
10264 },
10265 [ALC882_6ST_DIG] = {
10266 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010267 .init_verbs = { alc882_base_init_verbs,
10268 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010269 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10270 .dac_nids = alc882_dac_nids,
10271 .dig_out_nid = ALC882_DIGOUT_NID,
10272 .dig_in_nid = ALC882_DIGIN_NID,
10273 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10274 .channel_mode = alc882_sixstack_modes,
10275 .input_mux = &alc882_capture_source,
10276 },
10277 [ALC882_ARIMA] = {
10278 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010279 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10280 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010281 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10282 .dac_nids = alc882_dac_nids,
10283 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10284 .channel_mode = alc882_sixstack_modes,
10285 .input_mux = &alc882_capture_source,
10286 },
10287 [ALC882_W2JC] = {
10288 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010289 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10290 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010291 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10292 .dac_nids = alc882_dac_nids,
10293 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10294 .channel_mode = alc880_threestack_modes,
10295 .need_dac_fix = 1,
10296 .input_mux = &alc882_capture_source,
10297 .dig_out_nid = ALC882_DIGOUT_NID,
10298 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010299 [ALC885_MBA21] = {
10300 .mixers = { alc885_mba21_mixer },
10301 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10302 .num_dacs = 2,
10303 .dac_nids = alc882_dac_nids,
10304 .channel_mode = alc885_mba21_ch_modes,
10305 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10306 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010307 .unsol_event = alc_sku_unsol_event,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010308 .setup = alc885_mba21_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010309 .init_hook = alc_hp_automute,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010310 },
Takashi Iwai49535502009-06-30 15:28:30 +020010311 [ALC885_MBP3] = {
10312 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10313 .init_verbs = { alc885_mbp3_init_verbs,
10314 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010315 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +020010316 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010317 .hp_nid = 0x04,
10318 .channel_mode = alc885_mbp_4ch_modes,
10319 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +020010320 .input_mux = &alc882_capture_source,
10321 .dig_out_nid = ALC882_DIGOUT_NID,
10322 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010323 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010324 .setup = alc885_mbp3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010325 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010326 },
10327 [ALC885_MB5] = {
10328 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10329 .init_verbs = { alc885_mb5_init_verbs,
10330 alc880_gpio1_init_verbs },
10331 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10332 .dac_nids = alc882_dac_nids,
10333 .channel_mode = alc885_mb5_6ch_modes,
10334 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10335 .input_mux = &mb5_capture_source,
10336 .dig_out_nid = ALC882_DIGOUT_NID,
10337 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010338 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010339 .setup = alc885_mb5_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010340 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010341 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010342 [ALC885_MACMINI3] = {
10343 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10344 .init_verbs = { alc885_macmini3_init_verbs,
10345 alc880_gpio1_init_verbs },
10346 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10347 .dac_nids = alc882_dac_nids,
10348 .channel_mode = alc885_macmini3_6ch_modes,
10349 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10350 .input_mux = &macmini3_capture_source,
10351 .dig_out_nid = ALC882_DIGOUT_NID,
10352 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010353 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010354 .setup = alc885_macmini3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010355 .init_hook = alc_hp_automute,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010356 },
Takashi Iwai49535502009-06-30 15:28:30 +020010357 [ALC885_MACPRO] = {
10358 .mixers = { alc882_macpro_mixer },
10359 .init_verbs = { alc882_macpro_init_verbs },
10360 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10361 .dac_nids = alc882_dac_nids,
10362 .dig_out_nid = ALC882_DIGOUT_NID,
10363 .dig_in_nid = ALC882_DIGIN_NID,
10364 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10365 .channel_mode = alc882_ch_modes,
10366 .input_mux = &alc882_capture_source,
10367 .init_hook = alc885_macpro_init_hook,
10368 },
10369 [ALC885_IMAC24] = {
10370 .mixers = { alc885_imac24_mixer },
10371 .init_verbs = { alc885_imac24_init_verbs },
10372 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10373 .dac_nids = alc882_dac_nids,
10374 .dig_out_nid = ALC882_DIGOUT_NID,
10375 .dig_in_nid = ALC882_DIGIN_NID,
10376 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10377 .channel_mode = alc882_ch_modes,
10378 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010379 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010380 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +020010381 .init_hook = alc885_imac24_init_hook,
10382 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010383 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010384 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010385 .init_verbs = { alc885_imac91_init_verbs,
10386 alc880_gpio1_init_verbs },
10387 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10388 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010389 .channel_mode = alc885_mba21_ch_modes,
10390 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10391 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010392 .dig_out_nid = ALC882_DIGOUT_NID,
10393 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010394 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010395 .setup = alc885_imac91_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010396 .init_hook = alc_hp_automute,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010397 },
Takashi Iwai49535502009-06-30 15:28:30 +020010398 [ALC882_TARGA] = {
10399 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010400 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010401 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010402 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10403 .dac_nids = alc882_dac_nids,
10404 .dig_out_nid = ALC882_DIGOUT_NID,
10405 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10406 .adc_nids = alc882_adc_nids,
10407 .capsrc_nids = alc882_capsrc_nids,
10408 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10409 .channel_mode = alc882_3ST_6ch_modes,
10410 .need_dac_fix = 1,
10411 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010412 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010413 .setup = alc882_targa_setup,
10414 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010415 },
10416 [ALC882_ASUS_A7J] = {
10417 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010418 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10419 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010420 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10421 .dac_nids = alc882_dac_nids,
10422 .dig_out_nid = ALC882_DIGOUT_NID,
10423 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10424 .adc_nids = alc882_adc_nids,
10425 .capsrc_nids = alc882_capsrc_nids,
10426 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10427 .channel_mode = alc882_3ST_6ch_modes,
10428 .need_dac_fix = 1,
10429 .input_mux = &alc882_capture_source,
10430 },
10431 [ALC882_ASUS_A7M] = {
10432 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010433 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10434 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010435 alc882_asus_a7m_verbs },
10436 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10437 .dac_nids = alc882_dac_nids,
10438 .dig_out_nid = ALC882_DIGOUT_NID,
10439 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10440 .channel_mode = alc880_threestack_modes,
10441 .need_dac_fix = 1,
10442 .input_mux = &alc882_capture_source,
10443 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010444 [ALC883_3ST_2ch_DIG] = {
10445 .mixers = { alc883_3ST_2ch_mixer },
10446 .init_verbs = { alc883_init_verbs },
10447 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10448 .dac_nids = alc883_dac_nids,
10449 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010450 .dig_in_nid = ALC883_DIGIN_NID,
10451 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10452 .channel_mode = alc883_3ST_2ch_modes,
10453 .input_mux = &alc883_capture_source,
10454 },
10455 [ALC883_3ST_6ch_DIG] = {
10456 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10457 .init_verbs = { alc883_init_verbs },
10458 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10459 .dac_nids = alc883_dac_nids,
10460 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010461 .dig_in_nid = ALC883_DIGIN_NID,
10462 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10463 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010464 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010465 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010466 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010467 [ALC883_3ST_6ch] = {
10468 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10469 .init_verbs = { alc883_init_verbs },
10470 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10471 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010472 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10473 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010474 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010475 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010476 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010477 [ALC883_3ST_6ch_INTEL] = {
10478 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10479 .init_verbs = { alc883_init_verbs },
10480 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10481 .dac_nids = alc883_dac_nids,
10482 .dig_out_nid = ALC883_DIGOUT_NID,
10483 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010484 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010485 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10486 .channel_mode = alc883_3ST_6ch_intel_modes,
10487 .need_dac_fix = 1,
10488 .input_mux = &alc883_3stack_6ch_intel,
10489 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010490 [ALC889A_INTEL] = {
10491 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010492 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10493 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010494 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10495 .dac_nids = alc883_dac_nids,
10496 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10497 .adc_nids = alc889_adc_nids,
10498 .dig_out_nid = ALC883_DIGOUT_NID,
10499 .dig_in_nid = ALC883_DIGIN_NID,
10500 .slave_dig_outs = alc883_slave_dig_outs,
10501 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10502 .channel_mode = alc889_8ch_intel_modes,
10503 .capsrc_nids = alc889_capsrc_nids,
10504 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010505 .setup = alc889_automute_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010506 .init_hook = alc_hp_automute,
10507 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010508 .need_dac_fix = 1,
10509 },
10510 [ALC889_INTEL] = {
10511 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10512 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010513 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010514 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10515 .dac_nids = alc883_dac_nids,
10516 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10517 .adc_nids = alc889_adc_nids,
10518 .dig_out_nid = ALC883_DIGOUT_NID,
10519 .dig_in_nid = ALC883_DIGIN_NID,
10520 .slave_dig_outs = alc883_slave_dig_outs,
10521 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10522 .channel_mode = alc889_8ch_intel_modes,
10523 .capsrc_nids = alc889_capsrc_nids,
10524 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010525 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010526 .init_hook = alc889_intel_init_hook,
Takashi Iwaid922b512011-04-28 12:18:53 +020010527 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010528 .need_dac_fix = 1,
10529 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010530 [ALC883_6ST_DIG] = {
10531 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10532 .init_verbs = { alc883_init_verbs },
10533 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10534 .dac_nids = alc883_dac_nids,
10535 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010536 .dig_in_nid = ALC883_DIGIN_NID,
10537 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10538 .channel_mode = alc883_sixstack_modes,
10539 .input_mux = &alc883_capture_source,
10540 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010541 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010542 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010543 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10544 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010545 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10546 .dac_nids = alc883_dac_nids,
10547 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010548 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10549 .channel_mode = alc883_3ST_6ch_modes,
10550 .need_dac_fix = 1,
10551 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010552 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010553 .setup = alc882_targa_setup,
10554 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010555 },
10556 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010557 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010558 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10559 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010560 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10561 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010562 .adc_nids = alc883_adc_nids_alt,
10563 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010564 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010565 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010566 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10567 .channel_mode = alc883_3ST_2ch_modes,
10568 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010569 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010570 .setup = alc882_targa_setup,
10571 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010572 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010573 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010574 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10575 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010576 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010577 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010578 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10579 .dac_nids = alc883_dac_nids,
10580 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10581 .adc_nids = alc883_adc_nids_rev,
10582 .capsrc_nids = alc883_capsrc_nids_rev,
10583 .dig_out_nid = ALC883_DIGOUT_NID,
10584 .dig_in_nid = ALC883_DIGIN_NID,
10585 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10586 .channel_mode = alc883_4ST_8ch_modes,
10587 .need_dac_fix = 1,
10588 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010589 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010590 .setup = alc882_targa_setup,
10591 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010592 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010593 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010594 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010595 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10596 * and the headphone jack. Turn this on and rely on the
10597 * standard mute methods whenever the user wants to turn
10598 * these outputs off.
10599 */
10600 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10601 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10602 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010603 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10604 .channel_mode = alc883_3ST_2ch_modes,
10605 .input_mux = &alc883_capture_source,
10606 },
Tobin Davis2880a862007-08-07 11:50:26 +020010607 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010608 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010609 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010610 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10611 .dac_nids = alc883_dac_nids,
10612 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010613 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10614 .channel_mode = alc883_3ST_2ch_modes,
10615 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010616 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010617 .setup = alc883_acer_aspire_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010618 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010619 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010620 [ALC888_ACER_ASPIRE_4930G] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +010010621 .mixers = { alc888_acer_aspire_4930g_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010622 alc883_chmode_mixer },
10623 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10624 alc888_acer_aspire_4930g_verbs },
10625 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10626 .dac_nids = alc883_dac_nids,
10627 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10628 .adc_nids = alc883_adc_nids_rev,
10629 .capsrc_nids = alc883_capsrc_nids_rev,
10630 .dig_out_nid = ALC883_DIGOUT_NID,
10631 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10632 .channel_mode = alc883_3ST_6ch_modes,
10633 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010634 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010635 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010636 ARRAY_SIZE(alc888_2_capture_sources),
10637 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010638 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010639 .setup = alc888_acer_aspire_4930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010640 .init_hook = alc_hp_automute,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010641 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010642 [ALC888_ACER_ASPIRE_6530G] = {
10643 .mixers = { alc888_acer_aspire_6530_mixer },
10644 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10645 alc888_acer_aspire_6530g_verbs },
10646 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10647 .dac_nids = alc883_dac_nids,
10648 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10649 .adc_nids = alc883_adc_nids_rev,
10650 .capsrc_nids = alc883_capsrc_nids_rev,
10651 .dig_out_nid = ALC883_DIGOUT_NID,
10652 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10653 .channel_mode = alc883_3ST_2ch_modes,
10654 .num_mux_defs =
10655 ARRAY_SIZE(alc888_2_capture_sources),
10656 .input_mux = alc888_acer_aspire_6530_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010657 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010658 .setup = alc888_acer_aspire_6530g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010659 .init_hook = alc_hp_automute,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010660 },
Hector Martin3b315d72009-06-02 10:54:19 +020010661 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010662 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010663 alc883_chmode_mixer },
10664 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010665 alc889_acer_aspire_8930g_verbs,
10666 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010667 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10668 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010669 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10670 .adc_nids = alc889_adc_nids,
10671 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010672 .dig_out_nid = ALC883_DIGOUT_NID,
10673 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10674 .channel_mode = alc883_3ST_6ch_modes,
10675 .need_dac_fix = 1,
10676 .const_channel_count = 6,
10677 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010678 ARRAY_SIZE(alc889_capture_sources),
10679 .input_mux = alc889_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010680 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010681 .setup = alc889_acer_aspire_8930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010682 .init_hook = alc_hp_automute,
Hector Martinf5de24b2009-12-20 22:51:31 +010010683#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010684 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010685#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010686 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010687 [ALC888_ACER_ASPIRE_7730G] = {
10688 .mixers = { alc883_3ST_6ch_mixer,
10689 alc883_chmode_mixer },
10690 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10691 alc888_acer_aspire_7730G_verbs },
10692 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10693 .dac_nids = alc883_dac_nids,
10694 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10695 .adc_nids = alc883_adc_nids_rev,
10696 .capsrc_nids = alc883_capsrc_nids_rev,
10697 .dig_out_nid = ALC883_DIGOUT_NID,
10698 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10699 .channel_mode = alc883_3ST_6ch_modes,
10700 .need_dac_fix = 1,
10701 .const_channel_count = 6,
10702 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010703 .unsol_event = alc_sku_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010704 .setup = alc888_acer_aspire_7730g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010705 .init_hook = alc_hp_automute,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010706 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010707 [ALC883_MEDION] = {
10708 .mixers = { alc883_fivestack_mixer,
10709 alc883_chmode_mixer },
10710 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010711 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010712 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10713 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010714 .adc_nids = alc883_adc_nids_alt,
10715 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010716 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010717 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10718 .channel_mode = alc883_sixstack_modes,
10719 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010720 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010721 [ALC883_MEDION_WIM2160] = {
10722 .mixers = { alc883_medion_wim2160_mixer },
10723 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10724 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10725 .dac_nids = alc883_dac_nids,
10726 .dig_out_nid = ALC883_DIGOUT_NID,
10727 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10728 .adc_nids = alc883_adc_nids,
10729 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10730 .channel_mode = alc883_3ST_2ch_modes,
10731 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010732 .unsol_event = alc_sku_unsol_event,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010733 .setup = alc883_medion_wim2160_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010734 .init_hook = alc_hp_automute,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010735 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010736 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010737 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010738 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10739 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10740 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010741 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10742 .channel_mode = alc883_3ST_2ch_modes,
10743 .input_mux = &alc883_capture_source,
10744 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010745 [ALC883_CLEVO_M540R] = {
10746 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10747 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10748 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10749 .dac_nids = alc883_dac_nids,
10750 .dig_out_nid = ALC883_DIGOUT_NID,
10751 .dig_in_nid = ALC883_DIGIN_NID,
10752 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10753 .channel_mode = alc883_3ST_6ch_clevo_modes,
10754 .need_dac_fix = 1,
10755 .input_mux = &alc883_capture_source,
10756 /* This machine has the hardware HP auto-muting, thus
10757 * we need no software mute via unsol event
10758 */
10759 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010760 [ALC883_CLEVO_M720] = {
10761 .mixers = { alc883_clevo_m720_mixer },
10762 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010763 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10764 .dac_nids = alc883_dac_nids,
10765 .dig_out_nid = ALC883_DIGOUT_NID,
10766 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10767 .channel_mode = alc883_3ST_2ch_modes,
10768 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010769 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010770 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010771 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010772 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010773 [ALC883_LENOVO_101E_2ch] = {
10774 .mixers = { alc883_lenovo_101e_2ch_mixer},
10775 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10776 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10777 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010778 .adc_nids = alc883_adc_nids_alt,
10779 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010780 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010781 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10782 .channel_mode = alc883_3ST_2ch_modes,
10783 .input_mux = &alc883_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010784 .setup = alc883_lenovo_101e_setup,
10785 .unsol_event = alc_sku_unsol_event,
10786 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010787 },
Kailang Yang272a5272007-05-14 11:00:38 +020010788 [ALC883_LENOVO_NB0763] = {
10789 .mixers = { alc883_lenovo_nb0763_mixer },
10790 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10791 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10792 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010793 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10794 .channel_mode = alc883_3ST_2ch_modes,
10795 .need_dac_fix = 1,
10796 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010797 .unsol_event = alc_sku_unsol_event,
Takashi Iwaidc427172010-11-29 07:42:59 +010010798 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010799 .init_hook = alc_hp_automute,
Kailang Yang272a5272007-05-14 11:00:38 +020010800 },
10801 [ALC888_LENOVO_MS7195_DIG] = {
10802 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10803 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10804 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10805 .dac_nids = alc883_dac_nids,
10806 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010807 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10808 .channel_mode = alc883_3ST_6ch_modes,
10809 .need_dac_fix = 1,
10810 .input_mux = &alc883_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010811 .unsol_event = alc_sku_unsol_event,
10812 .setup = alc888_lenovo_ms7195_setup,
10813 .init_hook = alc_inithook,
Kailang Yang189609a2007-08-20 11:31:23 +020010814 },
10815 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010816 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010817 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10818 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10819 .dac_nids = alc883_dac_nids,
10820 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010821 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10822 .channel_mode = alc883_3ST_2ch_modes,
10823 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010824 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010825 .setup = alc883_haier_w66_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010826 .init_hook = alc_hp_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010827 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010828 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010829 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010830 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010831 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10832 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010833 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10834 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010835 .need_dac_fix = 1,
10836 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010837 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010838 .setup = alc888_3st_hp_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010839 .init_hook = alc_hp_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010840 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010841 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010842 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010843 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10844 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10845 .dac_nids = alc883_dac_nids,
10846 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010847 .dig_in_nid = ALC883_DIGIN_NID,
10848 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10849 .channel_mode = alc883_sixstack_modes,
10850 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010851 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010852 .setup = alc888_6st_dell_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010853 .init_hook = alc_hp_automute,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010854 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010855 [ALC883_MITAC] = {
10856 .mixers = { alc883_mitac_mixer },
10857 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10858 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10859 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010860 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10861 .channel_mode = alc883_3ST_2ch_modes,
10862 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010863 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010864 .setup = alc883_mitac_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010865 .init_hook = alc_hp_automute,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010866 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010867 [ALC883_FUJITSU_PI2515] = {
10868 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10869 .init_verbs = { alc883_init_verbs,
10870 alc883_2ch_fujitsu_pi2515_verbs},
10871 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10872 .dac_nids = alc883_dac_nids,
10873 .dig_out_nid = ALC883_DIGOUT_NID,
10874 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10875 .channel_mode = alc883_3ST_2ch_modes,
10876 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010877 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010878 .setup = alc883_2ch_fujitsu_pi2515_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010879 .init_hook = alc_hp_automute,
Jiang zhefb97dc62008-03-06 11:07:11 +010010880 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010881 [ALC888_FUJITSU_XA3530] = {
10882 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10883 .init_verbs = { alc883_init_verbs,
10884 alc888_fujitsu_xa3530_verbs },
10885 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10886 .dac_nids = alc883_dac_nids,
10887 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10888 .adc_nids = alc883_adc_nids_rev,
10889 .capsrc_nids = alc883_capsrc_nids_rev,
10890 .dig_out_nid = ALC883_DIGOUT_NID,
10891 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10892 .channel_mode = alc888_4ST_8ch_intel_modes,
10893 .num_mux_defs =
10894 ARRAY_SIZE(alc888_2_capture_sources),
10895 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010896 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010897 .setup = alc888_fujitsu_xa3530_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010898 .init_hook = alc_hp_automute,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010899 },
Kailang Yange2757d52008-08-26 13:17:46 +020010900 [ALC888_LENOVO_SKY] = {
10901 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10902 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10903 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10904 .dac_nids = alc883_dac_nids,
10905 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010906 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10907 .channel_mode = alc883_sixstack_modes,
10908 .need_dac_fix = 1,
10909 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010910 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010911 .setup = alc888_lenovo_sky_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010912 .init_hook = alc_hp_automute,
Kailang Yange2757d52008-08-26 13:17:46 +020010913 },
10914 [ALC888_ASUS_M90V] = {
10915 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10916 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10917 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10918 .dac_nids = alc883_dac_nids,
10919 .dig_out_nid = ALC883_DIGOUT_NID,
10920 .dig_in_nid = ALC883_DIGIN_NID,
10921 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10922 .channel_mode = alc883_3ST_6ch_modes,
10923 .need_dac_fix = 1,
10924 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010925 .unsol_event = alc_sku_unsol_event,
10926 .setup = alc883_mode2_setup,
10927 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010928 },
10929 [ALC888_ASUS_EEE1601] = {
10930 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010931 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010932 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10933 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10934 .dac_nids = alc883_dac_nids,
10935 .dig_out_nid = ALC883_DIGOUT_NID,
10936 .dig_in_nid = ALC883_DIGIN_NID,
10937 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10938 .channel_mode = alc883_3ST_2ch_modes,
10939 .need_dac_fix = 1,
10940 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010941 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010942 .init_hook = alc883_eee1601_inithook,
10943 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010944 [ALC1200_ASUS_P5Q] = {
10945 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10946 .init_verbs = { alc883_init_verbs },
10947 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10948 .dac_nids = alc883_dac_nids,
10949 .dig_out_nid = ALC1200_DIGOUT_NID,
10950 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010951 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010952 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10953 .channel_mode = alc883_sixstack_modes,
10954 .input_mux = &alc883_capture_source,
10955 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010956 [ALC889A_MB31] = {
10957 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10958 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10959 alc880_gpio1_init_verbs },
10960 .adc_nids = alc883_adc_nids,
10961 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010962 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010963 .dac_nids = alc883_dac_nids,
10964 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10965 .channel_mode = alc889A_mb31_6ch_modes,
10966 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10967 .input_mux = &alc889A_mb31_capture_source,
10968 .dig_out_nid = ALC883_DIGOUT_NID,
10969 .unsol_event = alc889A_mb31_unsol_event,
10970 .init_hook = alc889A_mb31_automute,
10971 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010972 [ALC883_SONY_VAIO_TT] = {
10973 .mixers = { alc883_vaiott_mixer },
10974 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10975 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10976 .dac_nids = alc883_dac_nids,
10977 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10978 .channel_mode = alc883_3ST_2ch_modes,
10979 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010980 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010981 .setup = alc883_vaiott_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010982 .init_hook = alc_hp_automute,
Guido Günther3e1647c2009-06-05 00:47:26 +020010983 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010984};
10985
10986
10987/*
Takashi Iwai49535502009-06-30 15:28:30 +020010988 * Pin config fixes
10989 */
10990enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010991 PINFIX_ABIT_AW9D_MAX,
David Henningsson32eea382011-03-04 13:37:50 +010010992 PINFIX_LENOVO_Y530,
Takashi Iwai954a29c2010-07-30 10:55:44 +020010993 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010994 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai49535502009-06-30 15:28:30 +020010995};
10996
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010997static const struct alc_fixup alc882_fixups[] = {
10998 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010999 .type = ALC_FIXUP_PINS,
11000 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020011001 { 0x15, 0x01080104 }, /* side */
11002 { 0x16, 0x01011012 }, /* rear */
11003 { 0x17, 0x01016011 }, /* clfe */
11004 { }
11005 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020011006 },
David Henningsson32eea382011-03-04 13:37:50 +010011007 [PINFIX_LENOVO_Y530] = {
11008 .type = ALC_FIXUP_PINS,
11009 .v.pins = (const struct alc_pincfg[]) {
11010 { 0x15, 0x99130112 }, /* rear int speakers */
11011 { 0x16, 0x99130111 }, /* subwoofer */
11012 { }
11013 }
11014 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020011015 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011016 .type = ALC_FIXUP_VERBS,
11017 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020011018 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
11019 {}
11020 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020011021 },
David Henningssonc3d226a2010-10-14 15:42:08 +020011022 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011023 .type = ALC_FIXUP_SKU,
11024 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020011025 },
Takashi Iwai49535502009-06-30 15:28:30 +020011026};
11027
Takashi Iwaia9111322011-05-02 11:30:18 +020011028static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020011029 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
David Henningsson32eea382011-03-04 13:37:50 +010011030 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
Takashi Iwai49535502009-06-30 15:28:30 +020011031 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020011032 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai49535502009-06-30 15:28:30 +020011033 {}
11034};
11035
11036/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011037 * BIOS auto configuration
11038 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020011039static int alc882_auto_create_input_ctls(struct hda_codec *codec,
11040 const struct auto_pin_cfg *cfg)
11041{
11042 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
11043}
11044
Takashi Iwai49535502009-06-30 15:28:30 +020011045static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011046 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020011047 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011048{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011049 int idx;
11050
Takashi Iwai489008c2010-04-07 09:06:00 +020011051 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011052 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011053
Takashi Iwai489008c2010-04-07 09:06:00 +020011054 if (dac == 0x25)
11055 idx = 4;
11056 else if (dac >= 0x02 && dac <= 0x05)
11057 idx = dac - 2;
11058 else
11059 return;
11060 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011061}
11062
Takashi Iwai49535502009-06-30 15:28:30 +020011063static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011064{
11065 struct alc_spec *spec = codec->spec;
11066 int i;
11067
11068 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011069 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011070 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011071 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020011072 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020011073 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011074 }
11075}
11076
Takashi Iwai49535502009-06-30 15:28:30 +020011077static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011078{
11079 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020011080 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020011081 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011082
David Henningsson0a3fabe2011-03-04 16:54:52 +010011083 if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
11084 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
11085 pin = spec->autocfg.hp_pins[i];
11086 if (!pin)
11087 break;
11088 dac = spec->multiout.hp_nid;
11089 if (!dac)
11090 dac = spec->multiout.dac_nids[0]; /* to front */
11091 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
11092 }
Takashi Iwai489008c2010-04-07 09:06:00 +020011093 }
David Henningsson0a3fabe2011-03-04 16:54:52 +010011094
11095 if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
11096 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
11097 pin = spec->autocfg.speaker_pins[i];
11098 if (!pin)
11099 break;
11100 dac = spec->multiout.extra_out_nid[0];
11101 if (!dac)
11102 dac = spec->multiout.dac_nids[0]; /* to front */
11103 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
11104 }
Takashi Iwai489008c2010-04-07 09:06:00 +020011105 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011106}
11107
Takashi Iwai49535502009-06-30 15:28:30 +020011108static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011109{
11110 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011111 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011112 int i;
11113
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011114 for (i = 0; i < cfg->num_inputs; i++) {
11115 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020011116 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai49535502009-06-30 15:28:30 +020011117 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
11118 snd_hda_codec_write(codec, nid, 0,
11119 AC_VERB_SET_AMP_GAIN_MUTE,
11120 AMP_OUT_MUTE);
11121 }
11122}
11123
11124static void alc882_auto_init_input_src(struct hda_codec *codec)
11125{
11126 struct alc_spec *spec = codec->spec;
11127 int c;
11128
11129 for (c = 0; c < spec->num_adc_nids; c++) {
11130 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
11131 hda_nid_t nid = spec->capsrc_nids[c];
11132 unsigned int mux_idx;
11133 const struct hda_input_mux *imux;
11134 int conns, mute, idx, item;
11135
Takashi Iwai10696aa2011-04-07 12:46:45 +020011136 /* mute ADC */
11137 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
11138 AC_VERB_SET_AMP_GAIN_MUTE,
11139 AMP_IN_MUTE(0));
11140
Takashi Iwai49535502009-06-30 15:28:30 +020011141 conns = snd_hda_get_connections(codec, nid, conn_list,
11142 ARRAY_SIZE(conn_list));
11143 if (conns < 0)
11144 continue;
11145 mux_idx = c >= spec->num_mux_defs ? 0 : c;
11146 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010011147 if (!imux->num_items && mux_idx > 0)
11148 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020011149 for (idx = 0; idx < conns; idx++) {
11150 /* if the current connection is the selected one,
11151 * unmute it as default - otherwise mute it
11152 */
11153 mute = AMP_IN_MUTE(idx);
11154 for (item = 0; item < imux->num_items; item++) {
11155 if (imux->items[item].index == idx) {
11156 if (spec->cur_mux[c] == item)
11157 mute = AMP_IN_UNMUTE(idx);
11158 break;
11159 }
11160 }
11161 /* check if we have a selector or mixer
11162 * we could check for the widget type instead, but
11163 * just check for Amp-In presence (in case of mixer
11164 * without amp-in there is something wrong, this
11165 * function shouldn't be used or capsrc nid is wrong)
11166 */
11167 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011168 snd_hda_codec_write(codec, nid, 0,
11169 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020011170 mute);
11171 else if (mute != AMP_IN_MUTE(idx))
11172 snd_hda_codec_write(codec, nid, 0,
11173 AC_VERB_SET_CONNECT_SEL,
11174 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011175 }
11176 }
11177}
11178
Takashi Iwai49535502009-06-30 15:28:30 +020011179/* add mic boosts if needed */
11180static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011181{
11182 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011183 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010011184 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010011185 int type_idx = 0;
Takashi Iwai49535502009-06-30 15:28:30 +020011186 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010011187 const char *prev_label = NULL;
Takashi Iwai49535502009-06-30 15:28:30 +020011188
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011189 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020011190 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011191 break;
11192 nid = cfg->inputs[i].pin;
11193 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010011194 const char *label;
11195 char boost_label[32];
11196
11197 label = hda_get_autocfg_input_label(codec, cfg, i);
11198 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010011199 type_idx++;
11200 else
11201 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010011202 prev_label = label;
11203
11204 snprintf(boost_label, sizeof(boost_label),
11205 "%s Boost Volume", label);
11206 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11207 boost_label, type_idx,
Takashi Iwai49535502009-06-30 15:28:30 +020011208 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011209 if (err < 0)
11210 return err;
11211 }
Takashi Iwai49535502009-06-30 15:28:30 +020011212 }
11213 return 0;
11214}
11215
11216/* almost identical with ALC880 parser... */
11217static int alc882_parse_auto_config(struct hda_codec *codec)
11218{
11219 struct alc_spec *spec = codec->spec;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011220 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020011221 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011222
Takashi Iwai05f5f472009-08-25 13:10:18 +020011223 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11224 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011225 if (err < 0)
11226 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011227 if (!spec->autocfg.line_outs)
11228 return 0; /* can't find valid BIOS pin config */
11229
11230 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
11231 if (err < 0)
11232 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020011233 err = alc_auto_add_multi_channel_mode(codec);
11234 if (err < 0)
11235 return err;
Takashi Iwai569ed342011-01-19 10:14:46 +010011236 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
Takashi Iwai05f5f472009-08-25 13:10:18 +020011237 if (err < 0)
11238 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020011239 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
11240 "Headphone");
11241 if (err < 0)
11242 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011243 err = alc880_auto_create_extra_out(spec,
11244 spec->autocfg.speaker_pins[0],
11245 "Speaker");
11246 if (err < 0)
11247 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011248 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
11249 if (err < 0)
11250 return err;
11251
11252 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11253
Takashi Iwai757899a2010-07-30 10:48:14 +020011254 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020011255
11256 if (spec->kctls.list)
11257 add_mixer(spec, spec->kctls.list);
11258
11259 add_verb(spec, alc883_auto_init_verbs);
11260 /* if ADC 0x07 is available, initialize it, too */
11261 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
11262 add_verb(spec, alc882_adc1_init_verbs);
11263
11264 spec->num_mux_defs = 1;
11265 spec->input_mux = &spec->private_imux[0];
11266
Kailang Yang6227cdc2010-02-25 08:36:52 +010011267 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020011268
11269 err = alc_auto_add_mic_boost(codec);
11270 if (err < 0)
11271 return err;
11272
Takashi Iwai776e1842007-08-29 15:07:11 +020011273 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011274}
11275
11276/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020011277static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011278{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011279 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020011280 alc882_auto_init_multi_out(codec);
11281 alc882_auto_init_hp_out(codec);
11282 alc882_auto_init_analog_input(codec);
11283 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020011284 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011285 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011286 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011287}
11288
Takashi Iwai49535502009-06-30 15:28:30 +020011289static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011290{
11291 struct alc_spec *spec;
11292 int err, board_config;
11293
11294 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
11295 if (spec == NULL)
11296 return -ENOMEM;
11297
11298 codec->spec = spec;
11299
Takashi Iwai49535502009-06-30 15:28:30 +020011300 switch (codec->vendor_id) {
11301 case 0x10ec0882:
11302 case 0x10ec0885:
11303 break;
11304 default:
11305 /* ALC883 and variants */
11306 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11307 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011308 }
11309
Takashi Iwai49535502009-06-30 15:28:30 +020011310 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
11311 alc882_models,
11312 alc882_cfg_tbl);
11313
11314 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
11315 board_config = snd_hda_check_board_codec_sid_config(codec,
11316 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
11317
11318 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020011319 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020011320 codec->chip_name);
11321 board_config = ALC882_AUTO;
11322 }
11323
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011324 if (board_config == ALC882_AUTO) {
11325 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
11326 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
11327 }
Takashi Iwai49535502009-06-30 15:28:30 +020011328
David Henningsson90622912010-10-14 14:50:18 +020011329 alc_auto_parse_customize_define(codec);
11330
Takashi Iwai49535502009-06-30 15:28:30 +020011331 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011332 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020011333 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011334 if (err < 0) {
11335 alc_free(codec);
11336 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011337 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011338 printk(KERN_INFO
11339 "hda_codec: Cannot set up configuration "
11340 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020011341 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011342 }
11343 }
11344
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011345 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011346 err = snd_hda_attach_beep_device(codec, 0x1);
11347 if (err < 0) {
11348 alc_free(codec);
11349 return err;
11350 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011351 }
11352
Takashi Iwai49535502009-06-30 15:28:30 +020011353 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011354 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011355
Takashi Iwai49535502009-06-30 15:28:30 +020011356 spec->stream_analog_playback = &alc882_pcm_analog_playback;
11357 spec->stream_analog_capture = &alc882_pcm_analog_capture;
11358 /* FIXME: setup DAC5 */
11359 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
11360 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
11361
11362 spec->stream_digital_playback = &alc882_pcm_digital_playback;
11363 spec->stream_digital_capture = &alc882_pcm_digital_capture;
11364
Takashi Iwai49535502009-06-30 15:28:30 +020011365 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011366 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020011367 spec->num_adc_nids = 0;
11368 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011369 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020011370 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011371 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020011372 hda_nid_t nid = alc882_adc_nids[i];
11373 unsigned int wcap = get_wcaps(codec, nid);
11374 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011375 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020011376 if (wcap != AC_WID_AUD_IN)
11377 continue;
11378 spec->private_adc_nids[spec->num_adc_nids] = nid;
11379 err = snd_hda_get_connections(codec, nid, &cap, 1);
11380 if (err < 0)
11381 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011382 err = snd_hda_get_connections(codec, cap, items,
11383 ARRAY_SIZE(items));
11384 if (err < 0)
11385 continue;
11386 for (j = 0; j < imux->num_items; j++)
11387 if (imux->items[j].index >= err)
11388 break;
11389 if (j < imux->num_items)
11390 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020011391 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
11392 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011393 }
Takashi Iwai49535502009-06-30 15:28:30 +020011394 spec->adc_nids = spec->private_adc_nids;
11395 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020011396 }
11397
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011398 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011399
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011400 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011401 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011402
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011403 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011404
Takashi Iwai2134ea42008-01-10 16:53:55 +010011405 spec->vmaster_nid = 0x0c;
11406
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011407 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020011408 if (board_config == ALC882_AUTO)
11409 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011410
11411 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011412#ifdef CONFIG_SND_HDA_POWER_SAVE
11413 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020011414 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011415#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011416
11417 return 0;
11418}
11419
Takashi Iwai49535502009-06-30 15:28:30 +020011420
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011421/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011422 * ALC262 support
11423 */
11424
11425#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11426#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11427
11428#define alc262_dac_nids alc260_dac_nids
11429#define alc262_adc_nids alc882_adc_nids
11430#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011431#define alc262_capsrc_nids alc882_capsrc_nids
11432#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011433
11434#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011435#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011436
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011437static const hda_nid_t alc262_dmic_adc_nids[1] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011438 /* ADC0 */
11439 0x09
11440};
11441
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011442static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
Kailang Yang4e555fe2008-08-26 13:05:55 +020011443
Takashi Iwaia9111322011-05-02 11:30:18 +020011444static const struct snd_kcontrol_new alc262_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011445 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11446 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11447 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11448 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11449 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11450 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11451 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11452 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011453 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011454 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11455 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011456 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011457 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11458 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11459 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11460 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011461 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011462};
11463
Takashi Iwaice875f02008-01-28 18:17:43 +010011464/* update HP, line and mono-out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011465#define alc262_hp_master_update alc260_hp_master_update
Takashi Iwaice875f02008-01-28 18:17:43 +010011466
Takashi Iwaie9427962011-04-28 15:46:07 +020011467static void alc262_hp_bpc_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011468{
11469 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011470
Takashi Iwaie9427962011-04-28 15:46:07 +020011471 spec->autocfg.hp_pins[0] = 0x1b;
11472 spec->autocfg.speaker_pins[0] = 0x16;
11473 spec->automute = 1;
11474 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011475}
11476
Takashi Iwaie9427962011-04-28 15:46:07 +020011477static void alc262_hp_wildwest_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011478{
11479 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011480
Takashi Iwaie9427962011-04-28 15:46:07 +020011481 spec->autocfg.hp_pins[0] = 0x15;
11482 spec->autocfg.speaker_pins[0] = 0x16;
11483 spec->automute = 1;
11484 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011485}
11486
Takashi Iwaib72519b2009-05-08 14:31:55 +020011487#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011488#define alc262_hp_master_sw_put alc260_hp_master_sw_put
Takashi Iwaice875f02008-01-28 18:17:43 +010011489
Takashi Iwaib72519b2009-05-08 14:31:55 +020011490#define ALC262_HP_MASTER_SWITCH \
11491 { \
11492 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11493 .name = "Master Playback Switch", \
11494 .info = snd_ctl_boolean_mono_info, \
11495 .get = alc262_hp_master_sw_get, \
11496 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011497 }, \
11498 { \
11499 .iface = NID_MAPPING, \
11500 .name = "Master Playback Switch", \
11501 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011502 }
11503
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011504
Takashi Iwaia9111322011-05-02 11:30:18 +020011505static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011506 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011507 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11508 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11509 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011510 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11511 HDA_OUTPUT),
11512 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11513 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11515 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011516 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011517 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11518 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011519 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011520 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11521 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11522 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11523 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011524 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11525 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11526 { } /* end */
11527};
11528
Takashi Iwaia9111322011-05-02 11:30:18 +020011529static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011530 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011531 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11532 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11533 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11534 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011535 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11536 HDA_OUTPUT),
11537 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11538 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011539 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11540 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011541 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011542 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11543 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11544 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11545 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011546 { } /* end */
11547};
11548
Takashi Iwaia9111322011-05-02 11:30:18 +020011549static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010011550 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11551 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011552 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011553 { } /* end */
11554};
11555
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011556/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011557static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011558{
11559 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011560
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011561 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011562 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020011563 spec->automute = 1;
11564 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011565}
11566
Takashi Iwaia9111322011-05-02 11:30:18 +020011567static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011568 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11569 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011570 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11571 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11572 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11573 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011574 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011575 { } /* end */
11576};
11577
Takashi Iwaia9111322011-05-02 11:30:18 +020011578static const struct hda_verb alc262_hp_t5735_verbs[] = {
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011579 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11580 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11581
11582 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11583 { }
11584};
11585
Takashi Iwaia9111322011-05-02 11:30:18 +020011586static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011587 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11588 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011589 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11590 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011591 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11592 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11593 { } /* end */
11594};
11595
Takashi Iwaia9111322011-05-02 11:30:18 +020011596static const struct hda_verb alc262_hp_rp5700_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010011597 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11598 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11599 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11600 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11601 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11602 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11603 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11604 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11605 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11606 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11607 {}
11608};
11609
Takashi Iwaia9111322011-05-02 11:30:18 +020011610static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
Kailang Yang8c427222008-01-10 13:03:59 +010011611 .num_items = 1,
11612 .items = {
11613 { "Line", 0x1 },
11614 },
11615};
11616
Takashi Iwai42171c12009-05-08 14:11:43 +020011617/* bind hp and internal speaker mute (with plug check) as master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011618#define alc262_hippo_master_update alc262_hp_master_update
Takashi Iwai42171c12009-05-08 14:11:43 +020011619#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011620#define alc262_hippo_master_sw_put alc262_hp_master_sw_put
Takashi Iwai5b319542007-07-26 11:49:22 +020011621
Takashi Iwai42171c12009-05-08 14:11:43 +020011622#define ALC262_HIPPO_MASTER_SWITCH \
11623 { \
11624 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11625 .name = "Master Playback Switch", \
11626 .info = snd_ctl_boolean_mono_info, \
11627 .get = alc262_hippo_master_sw_get, \
11628 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011629 }, \
11630 { \
11631 .iface = NID_MAPPING, \
11632 .name = "Master Playback Switch", \
11633 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11634 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011635 }
11636
Takashi Iwaia9111322011-05-02 11:30:18 +020011637static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011638 ALC262_HIPPO_MASTER_SWITCH,
11639 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11640 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11641 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11642 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11643 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11644 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11645 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011646 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011647 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11648 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011649 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011650 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11651 { } /* end */
11652};
11653
Takashi Iwaia9111322011-05-02 11:30:18 +020011654static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011655 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11656 ALC262_HIPPO_MASTER_SWITCH,
11657 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11658 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11659 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11660 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11661 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11662 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011663 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011664 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11665 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011666 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011667 { } /* end */
11668};
11669
11670/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011671static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011672{
11673 struct alc_spec *spec = codec->spec;
11674
11675 spec->autocfg.hp_pins[0] = 0x15;
11676 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011677 spec->automute = 1;
11678 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011679}
11680
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011681static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011682{
11683 struct alc_spec *spec = codec->spec;
11684
11685 spec->autocfg.hp_pins[0] = 0x1b;
11686 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011687 spec->automute = 1;
11688 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011689}
11690
11691
Takashi Iwaia9111322011-05-02 11:30:18 +020011692static const struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011693 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011694 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011695 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11696 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11697 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11698 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11699 { } /* end */
11700};
11701
Takashi Iwaia9111322011-05-02 11:30:18 +020011702static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011703 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11704 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011705 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11707 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11708 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11709 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11710 { } /* end */
11711};
Kailang Yang272a5272007-05-14 11:00:38 +020011712
Takashi Iwaia9111322011-05-02 11:30:18 +020011713static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011714 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11715 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11716 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11717 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11718 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11719 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11720 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11721 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011722 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011723 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11724 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011725 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011726 { } /* end */
11727};
11728
Takashi Iwaia9111322011-05-02 11:30:18 +020011729static const struct hda_verb alc262_tyan_verbs[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011730 /* Headphone automute */
11731 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11732 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11733 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11734
11735 /* P11 AUX_IN, white 4-pin connector */
11736 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11737 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11738 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11739 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11740
11741 {}
11742};
11743
11744/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011745static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011746{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011747 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011748
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011749 spec->autocfg.hp_pins[0] = 0x1b;
11750 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +020011751 spec->automute = 1;
11752 spec->automute_mode = ALC_AUTOMUTE_AMP;
Tony Vroonba340e82009-02-02 19:01:30 +000011753}
11754
Tony Vroonba340e82009-02-02 19:01:30 +000011755
Kailang Yangdf694da2005-12-05 19:42:22 +010011756#define alc262_capture_mixer alc882_capture_mixer
11757#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11758
11759/*
11760 * generic initialization of ADC, input mixers and output mixers
11761 */
Takashi Iwaia9111322011-05-02 11:30:18 +020011762static const struct hda_verb alc262_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011763 /*
11764 * Unmute ADC0-2 and set the default input to mic-in
11765 */
11766 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11767 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11768 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11769 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11770 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11771 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11772
Takashi Iwaicb53c622007-08-10 17:21:45 +020011773 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011774 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011775 * Note: PASD motherboards uses the Line In 2 as the input for
11776 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011777 */
11778 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011779 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11780 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11781 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11782 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11783 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011784
11785 /*
11786 * Set up output mixers (0x0c - 0x0e)
11787 */
11788 /* set vol=0 to output mixers */
11789 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11790 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11791 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11792 /* set up input amps for analog loopback */
11793 /* Amp Indices: DAC = 0, mixer = 1 */
11794 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11795 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11796 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11797 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11798 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11799 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11800
11801 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11802 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11803 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11804 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11805 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11806 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11807
11808 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11809 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11810 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11811 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11812 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011813
Kailang Yangdf694da2005-12-05 19:42:22 +010011814 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11815 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011816
Kailang Yangdf694da2005-12-05 19:42:22 +010011817 /* FIXME: use matrix-type input source selection */
11818 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11819 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11820 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11821 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11822 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11823 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11824 /* Input mixer2 */
11825 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11826 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11827 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11828 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11829 /* Input mixer3 */
11830 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11831 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11832 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011833 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011834
11835 { }
11836};
11837
Takashi Iwaia9111322011-05-02 11:30:18 +020011838static const struct hda_verb alc262_eapd_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011839 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11840 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11841 { }
11842};
11843
Takashi Iwaia9111322011-05-02 11:30:18 +020011844static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +020011845 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11846 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11847 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11848
11849 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11850 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11851 {}
11852};
11853
Takashi Iwaia9111322011-05-02 11:30:18 +020011854static const struct hda_verb alc262_sony_unsol_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020011855 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11856 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11857 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11858
11859 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11860 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011861 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011862};
11863
Takashi Iwaia9111322011-05-02 11:30:18 +020011864static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011865 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11866 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11867 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11868 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11869 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011870 { } /* end */
11871};
11872
Takashi Iwaia9111322011-05-02 11:30:18 +020011873static const struct hda_verb alc262_toshiba_s06_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011874 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11875 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11876 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11877 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11878 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11879 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11880 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11881 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11882 {}
11883};
11884
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011885static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011886{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011887 struct alc_spec *spec = codec->spec;
11888
11889 spec->autocfg.hp_pins[0] = 0x15;
11890 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011891 spec->ext_mic.pin = 0x18;
11892 spec->ext_mic.mux_idx = 0;
11893 spec->int_mic.pin = 0x12;
11894 spec->int_mic.mux_idx = 9;
11895 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020011896 spec->automute = 1;
11897 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011898}
11899
Takashi Iwai834be882006-03-01 14:16:17 +010011900/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011901 * nec model
11902 * 0x15 = headphone
11903 * 0x16 = internal speaker
11904 * 0x18 = external mic
11905 */
11906
Takashi Iwaia9111322011-05-02 11:30:18 +020011907static const struct snd_kcontrol_new alc262_nec_mixer[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011908 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11909 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11910
11911 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11912 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011913 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011914
11915 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11916 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11917 { } /* end */
11918};
11919
Takashi Iwaia9111322011-05-02 11:30:18 +020011920static const struct hda_verb alc262_nec_verbs[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011921 /* Unmute Speaker */
11922 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11923
11924 /* Headphone */
11925 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11926 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11927
11928 /* External mic to headphone */
11929 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11930 /* External mic to speaker */
11931 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11932 {}
11933};
11934
11935/*
Takashi Iwai834be882006-03-01 14:16:17 +010011936 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011937 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11938 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011939 */
11940
Takashi Iwai20f5e0b2011-06-10 09:31:54 +020011941#define ALC_HP_EVENT ALC880_HP_EVENT
Takashi Iwai834be882006-03-01 14:16:17 +010011942
Takashi Iwaia9111322011-05-02 11:30:18 +020011943static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
Takashi Iwai834be882006-03-01 14:16:17 +010011944 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11945 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011946 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11947 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011948 {}
11949};
11950
Takashi Iwaia9111322011-05-02 11:30:18 +020011951static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011952 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11953 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11954 {}
11955};
11956
Takashi Iwaia9111322011-05-02 11:30:18 +020011957static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
Daniel T Chene2595322009-12-19 18:19:02 -050011958 /* Front Mic pin: input vref at 50% */
11959 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11960 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11961 {}
11962};
11963
Takashi Iwaia9111322011-05-02 11:30:18 +020011964static const struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011965 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011966 .items = {
11967 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011968 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011969 { "CD", 0x4 },
11970 },
11971};
11972
Takashi Iwaia9111322011-05-02 11:30:18 +020011973static const struct hda_input_mux alc262_HP_capture_source = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011974 .num_items = 5,
11975 .items = {
11976 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011977 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011978 { "Line", 0x2 },
11979 { "CD", 0x4 },
11980 { "AUX IN", 0x6 },
11981 },
11982};
11983
Takashi Iwaia9111322011-05-02 11:30:18 +020011984static const struct hda_input_mux alc262_HP_D7000_capture_source = {
zhejiangaccbe492007-08-31 12:36:05 +020011985 .num_items = 4,
11986 .items = {
11987 { "Mic", 0x0 },
11988 { "Front Mic", 0x2 },
11989 { "Line", 0x1 },
11990 { "CD", 0x4 },
11991 },
11992};
11993
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011994static void alc262_fujitsu_setup(struct hda_codec *codec)
Takashi Iwai834be882006-03-01 14:16:17 +010011995{
11996 struct alc_spec *spec = codec->spec;
Takashi Iwai834be882006-03-01 14:16:17 +010011997
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011998 spec->autocfg.hp_pins[0] = 0x14;
11999 spec->autocfg.hp_pins[1] = 0x1b;
12000 spec->autocfg.speaker_pins[0] = 0x15;
12001 spec->automute = 1;
12002 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012003}
12004
Takashi Iwai834be882006-03-01 14:16:17 +010012005/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaia9111322011-05-02 11:30:18 +020012006static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020012007 .ops = &snd_hda_bind_vol,
12008 .values = {
12009 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
12010 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
12011 0
12012 },
12013};
Takashi Iwai834be882006-03-01 14:16:17 +010012014
Takashi Iwaia9111322011-05-02 11:30:18 +020012015static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020012016 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010012017 {
12018 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12019 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012020 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12021 .info = snd_ctl_boolean_mono_info,
12022 .get = alc262_hp_master_sw_get,
12023 .put = alc262_hp_master_sw_put,
Takashi Iwai834be882006-03-01 14:16:17 +010012024 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012025 {
12026 .iface = NID_MAPPING,
12027 .name = "Master Playback Switch",
12028 .private_value = 0x1b,
12029 },
Takashi Iwai834be882006-03-01 14:16:17 +010012030 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12031 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012032 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010012033 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12034 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012035 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010012036 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12037 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010012038 { } /* end */
12039};
12040
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012041static void alc262_lenovo_3000_setup(struct hda_codec *codec)
Jiang zhe0e31daf2008-03-20 12:12:39 +010012042{
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012043 struct alc_spec *spec = codec->spec;
Jiang zhe0e31daf2008-03-20 12:12:39 +010012044
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012045 spec->autocfg.hp_pins[0] = 0x1b;
12046 spec->autocfg.speaker_pins[0] = 0x14;
12047 spec->autocfg.speaker_pins[1] = 0x16;
12048 spec->automute = 1;
12049 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhe0e31daf2008-03-20 12:12:39 +010012050}
12051
Takashi Iwaia9111322011-05-02 11:30:18 +020012052static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010012053 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
12054 {
12055 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12056 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012057 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
12058 .info = snd_ctl_boolean_mono_info,
12059 .get = alc262_hp_master_sw_get,
12060 .put = alc262_hp_master_sw_put,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012061 },
12062 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12063 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012064 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012065 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12066 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012067 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010012068 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12069 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012070 { } /* end */
12071};
12072
Takashi Iwaia9111322011-05-02 11:30:18 +020012073static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012074 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020012075 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012076 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12077 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012078 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012079 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12080 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012081 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012082 { } /* end */
12083};
12084
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012085/* additional init verbs for Benq laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020012086static const struct hda_verb alc262_EAPD_verbs[] = {
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012087 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
12088 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
12089 {}
12090};
12091
Takashi Iwaia9111322011-05-02 11:30:18 +020012092static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
Kailang Yang83c34212007-07-05 11:43:05 +020012093 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12094 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12095
12096 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
12097 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
12098 {}
12099};
12100
Tobin Davisf651b502007-10-26 12:40:47 +020012101/* Samsung Q1 Ultra Vista model setup */
Takashi Iwaia9111322011-05-02 11:30:18 +020012102static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012103 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
12104 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020012105 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12106 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012107 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
12108 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020012109 { } /* end */
12110};
12111
Takashi Iwaia9111322011-05-02 11:30:18 +020012112static const struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012113 /* output mixer */
12114 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12115 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12116 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12117 /* speaker */
12118 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12119 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12120 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12121 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12122 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020012123 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012124 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12125 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12126 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12127 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12128 /* internal mic */
12129 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12130 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12131 /* ADC, choose mic */
12132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12133 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12134 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12135 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12136 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12137 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12138 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12139 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12140 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
12141 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020012142 {}
12143};
12144
Tobin Davisf651b502007-10-26 12:40:47 +020012145/* mute/unmute internal speaker according to the hp jack and mute state */
12146static void alc262_ultra_automute(struct hda_codec *codec)
12147{
12148 struct alc_spec *spec = codec->spec;
12149 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020012150
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012151 mute = 0;
12152 /* auto-mute only when HP is used as HP */
12153 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012154 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012155 if (spec->jack_present)
12156 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020012157 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012158 /* mute/unmute internal speaker */
12159 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12160 HDA_AMP_MUTE, mute);
12161 /* mute/unmute HP */
12162 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12163 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020012164}
12165
12166/* unsolicited event for HP jack sensing */
12167static void alc262_ultra_unsol_event(struct hda_codec *codec,
12168 unsigned int res)
12169{
12170 if ((res >> 26) != ALC880_HP_EVENT)
12171 return;
12172 alc262_ultra_automute(codec);
12173}
12174
Takashi Iwaia9111322011-05-02 11:30:18 +020012175static const struct hda_input_mux alc262_ultra_capture_source = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012176 .num_items = 2,
12177 .items = {
12178 { "Mic", 0x1 },
12179 { "Headphone", 0x7 },
12180 },
12181};
12182
12183static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
12184 struct snd_ctl_elem_value *ucontrol)
12185{
12186 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12187 struct alc_spec *spec = codec->spec;
12188 int ret;
12189
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012190 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012191 if (!ret)
12192 return 0;
12193 /* reprogram the HP pin as mic or HP according to the input source */
12194 snd_hda_codec_write_cache(codec, 0x15, 0,
12195 AC_VERB_SET_PIN_WIDGET_CONTROL,
12196 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
12197 alc262_ultra_automute(codec); /* mute/unmute HP */
12198 return ret;
12199}
12200
Takashi Iwaia9111322011-05-02 11:30:18 +020012201static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012202 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
12203 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
12204 {
12205 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12206 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012207 .info = alc_mux_enum_info,
12208 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012209 .put = alc262_ultra_mux_enum_put,
12210 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012211 {
12212 .iface = NID_MAPPING,
12213 .name = "Capture Source",
12214 .private_value = 0x15,
12215 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012216 { } /* end */
12217};
12218
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012219/* We use two mixers depending on the output pin; 0x16 is a mono output
12220 * and thus it's bound with a different mixer.
12221 * This function returns which mixer amp should be used.
12222 */
12223static int alc262_check_volbit(hda_nid_t nid)
12224{
12225 if (!nid)
12226 return 0;
12227 else if (nid == 0x16)
12228 return 2;
12229 else
12230 return 1;
12231}
12232
12233static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012234 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012235{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012236 unsigned long val;
12237 int vbit;
12238
12239 vbit = alc262_check_volbit(nid);
12240 if (!vbit)
12241 return 0;
12242 if (*vbits & vbit) /* a volume control for this mixer already there */
12243 return 0;
12244 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012245 if (vbit == 2)
12246 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
12247 else
12248 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012249 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012250}
12251
12252static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012253 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012254{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012255 unsigned long val;
12256
12257 if (!nid)
12258 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012259 if (nid == 0x16)
12260 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
12261 else
12262 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012263 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012264}
12265
Kailang Yangdf694da2005-12-05 19:42:22 +010012266/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012267static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
12268 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012269{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012270 const char *pfx;
12271 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020012272 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010012273
12274 spec->multiout.num_dacs = 1; /* only use one dac */
12275 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +020012276 spec->private_dac_nids[0] = 2;
Kailang Yangdf694da2005-12-05 19:42:22 +010012277
Takashi Iwaice764ab2011-04-27 16:35:23 +020012278 pfx = alc_get_line_out_pfx(spec, true);
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010012279 if (!pfx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012280 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012281 for (i = 0; i < 2; i++) {
12282 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12283 if (err < 0)
12284 return err;
12285 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12286 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12287 "Speaker", i);
12288 if (err < 0)
12289 return err;
12290 }
12291 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12292 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12293 "Headphone", i);
12294 if (err < 0)
12295 return err;
12296 }
12297 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012298
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012299 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12300 alc262_check_volbit(cfg->speaker_pins[0]) |
12301 alc262_check_volbit(cfg->hp_pins[0]);
12302 if (vbits == 1 || vbits == 2)
12303 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012304 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012305 for (i = 0; i < 2; i++) {
12306 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12307 &vbits, i);
12308 if (err < 0)
12309 return err;
12310 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12311 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12312 "Speaker", &vbits, i);
12313 if (err < 0)
12314 return err;
12315 }
12316 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12317 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12318 "Headphone", &vbits, i);
12319 if (err < 0)
12320 return err;
12321 }
12322 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012323 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012324}
12325
Takashi Iwai05f5f472009-08-25 13:10:18 +020012326#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012327 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012328
12329/*
12330 * generic initialization of ADC, input mixers and output mixers
12331 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012332static const struct hda_verb alc262_volume_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012333 /*
12334 * Unmute ADC0-2 and set the default input to mic-in
12335 */
12336 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12337 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12338 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12339 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12340 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12341 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12342
Takashi Iwaicb53c622007-08-10 17:21:45 +020012343 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012344 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012345 * Note: PASD motherboards uses the Line In 2 as the input for
12346 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012347 */
12348 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012349 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12350 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12351 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12352 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12353 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012354
12355 /*
12356 * Set up output mixers (0x0c - 0x0f)
12357 */
12358 /* set vol=0 to output mixers */
12359 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12360 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12361 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012362
Kailang Yangdf694da2005-12-05 19:42:22 +010012363 /* set up input amps for analog loopback */
12364 /* Amp Indices: DAC = 0, mixer = 1 */
12365 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12366 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12367 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12368 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12369 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12370 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12371
12372 /* FIXME: use matrix-type input source selection */
12373 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12374 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12376 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12377 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12379 /* Input mixer2 */
12380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12384 /* Input mixer3 */
12385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12389
12390 { }
12391};
12392
Takashi Iwaia9111322011-05-02 11:30:18 +020012393static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012394 /*
12395 * Unmute ADC0-2 and set the default input to mic-in
12396 */
12397 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12398 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12399 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12400 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12401 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12402 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12403
Takashi Iwaicb53c622007-08-10 17:21:45 +020012404 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012405 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012406 * Note: PASD motherboards uses the Line In 2 as the input for
12407 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012408 */
12409 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012410 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12411 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12412 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12413 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12414 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12415 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12416 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012417
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012418 /*
12419 * Set up output mixers (0x0c - 0x0e)
12420 */
12421 /* set vol=0 to output mixers */
12422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12423 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12424 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12425
12426 /* set up input amps for analog loopback */
12427 /* Amp Indices: DAC = 0, mixer = 1 */
12428 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12429 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12430 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12431 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12432 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12433 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12434
Takashi Iwaice875f02008-01-28 18:17:43 +010012435 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012436 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12437 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12438
12439 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12440 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12441
12442 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12443 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12444
12445 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12446 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12447 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12448 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12449 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12450
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012451 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012452 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12453 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012454 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012455 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12456 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12457
12458
12459 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012460 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12461 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012462 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012463 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12464 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12465 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12466 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12467 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12468 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12469 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12470 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012471 /* Input mixer2 */
12472 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012473 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12474 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12475 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12476 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12477 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12478 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12479 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12480 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012481 /* Input mixer3 */
12482 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012483 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12484 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12485 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12486 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12487 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12488 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12489 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12490 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012491
Takashi Iwaice875f02008-01-28 18:17:43 +010012492 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12493
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012494 { }
12495};
12496
Takashi Iwaia9111322011-05-02 11:30:18 +020012497static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010012498 /*
12499 * Unmute ADC0-2 and set the default input to mic-in
12500 */
12501 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12502 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12503 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12504 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12505 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12506 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12507
Takashi Iwaicb53c622007-08-10 17:21:45 +020012508 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012509 * mixer widget
12510 * Note: PASD motherboards uses the Line In 2 as the input for front
12511 * panel mic (mic 2)
12512 */
12513 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012514 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12515 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12516 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12517 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12518 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12519 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12520 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12521 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012522 /*
12523 * Set up output mixers (0x0c - 0x0e)
12524 */
12525 /* set vol=0 to output mixers */
12526 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12527 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12528 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12529
12530 /* set up input amps for analog loopback */
12531 /* Amp Indices: DAC = 0, mixer = 1 */
12532 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12533 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12534 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12535 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12536 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12537 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12538
12539
12540 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12541 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12542 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12543 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12544 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12545 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12546 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12547
12548 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12549 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12550
12551 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12552 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12553
12554 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12555 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12556 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12557 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12558 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12559 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12560
12561 /* FIXME: use matrix-type input source selection */
12562 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12563 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12564 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12565 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12566 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12567 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12568 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12569 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12570 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12571 /* Input mixer2 */
12572 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12573 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12574 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12575 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12576 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12577 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12578 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12579 /* Input mixer3 */
12580 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12581 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12582 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12583 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12584 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12585 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12586 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12587
Takashi Iwaice875f02008-01-28 18:17:43 +010012588 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12589
Kailang Yangcd7509a2007-01-26 18:33:17 +010012590 { }
12591};
12592
Takashi Iwaia9111322011-05-02 11:30:18 +020012593static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012594
12595 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12596 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12597 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12598
12599 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12600 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12601 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12602 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12603
12604 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12605 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12606 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12607 {}
12608};
12609
Takashi Iwai18675e42010-09-08 15:55:44 +020012610/*
12611 * Pin config fixes
12612 */
12613enum {
12614 PINFIX_FSC_H270,
David Henningssond2a19da2011-06-22 09:58:37 +020012615 PINFIX_HP_Z200,
Takashi Iwai18675e42010-09-08 15:55:44 +020012616};
12617
12618static const struct alc_fixup alc262_fixups[] = {
12619 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012620 .type = ALC_FIXUP_PINS,
12621 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012622 { 0x14, 0x99130110 }, /* speaker */
12623 { 0x15, 0x0221142f }, /* front HP */
12624 { 0x1b, 0x0121141f }, /* rear HP */
12625 { }
12626 }
12627 },
David Henningssond2a19da2011-06-22 09:58:37 +020012628 [PINFIX_HP_Z200] = {
12629 .type = ALC_FIXUP_PINS,
12630 .v.pins = (const struct alc_pincfg[]) {
12631 { 0x16, 0x99130120 }, /* internal speaker */
12632 { }
12633 }
12634 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012635};
12636
Takashi Iwaia9111322011-05-02 11:30:18 +020012637static const struct snd_pci_quirk alc262_fixup_tbl[] = {
David Henningssond2a19da2011-06-22 09:58:37 +020012638 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
Takashi Iwai18675e42010-09-08 15:55:44 +020012639 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12640 {}
12641};
12642
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012643
Takashi Iwaicb53c622007-08-10 17:21:45 +020012644#ifdef CONFIG_SND_HDA_POWER_SAVE
12645#define alc262_loopbacks alc880_loopbacks
12646#endif
12647
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012648/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012649#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12650#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12651#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12652#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12653
12654/*
12655 * BIOS auto configuration
12656 */
12657static int alc262_parse_auto_config(struct hda_codec *codec)
12658{
12659 struct alc_spec *spec = codec->spec;
12660 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012661 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012662
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012663 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12664 alc262_ignore);
12665 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012666 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012667 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012668 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012669 spec->multiout.max_channels = 2;
12670 spec->no_analog = 1;
12671 goto dig_only;
12672 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012673 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012674 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012675 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12676 if (err < 0)
12677 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012678 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012679 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012680 return err;
12681
12682 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12683
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012684 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012685 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012686
Takashi Iwai603c4012008-07-30 15:01:44 +020012687 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012688 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012689
Takashi Iwaid88897e2008-10-31 15:01:37 +010012690 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012691 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012692 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012693
Takashi Iwai776e1842007-08-29 15:07:11 +020012694 err = alc_auto_add_mic_boost(codec);
12695 if (err < 0)
12696 return err;
12697
Kailang Yang6227cdc2010-02-25 08:36:52 +010012698 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012699
Kailang Yangdf694da2005-12-05 19:42:22 +010012700 return 1;
12701}
12702
12703#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12704#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12705#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012706#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012707
12708
12709/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012710static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012711{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012712 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012713 alc262_auto_init_multi_out(codec);
12714 alc262_auto_init_hp_out(codec);
12715 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012716 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012717 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012718 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012719 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012720}
12721
12722/*
12723 * configuration and preset
12724 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012725static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012726 [ALC262_BASIC] = "basic",
12727 [ALC262_HIPPO] = "hippo",
12728 [ALC262_HIPPO_1] = "hippo_1",
12729 [ALC262_FUJITSU] = "fujitsu",
12730 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012731 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012732 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012733 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012734 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012735 [ALC262_BENQ_T31] = "benq-t31",
12736 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012737 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012738 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012739 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012740 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012741 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012742 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012743 [ALC262_AUTO] = "auto",
12744};
12745
Takashi Iwaia9111322011-05-02 11:30:18 +020012746static const struct snd_pci_quirk alc262_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012747 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012748 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012749 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12750 ALC262_HP_BPC),
12751 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12752 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012753 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12754 ALC262_HP_BPC),
David Henningssond2a19da2011-06-22 09:58:37 +020012755 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
12756 ALC262_AUTO),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012757 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12758 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012759 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012760 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012761 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012762 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012763 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012764 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012765 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012766 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012767 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12768 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12769 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012770 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12771 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012772 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012773 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012774 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012775 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012776 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012777 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012778 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012779 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012780#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012781 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12782 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012783#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012784 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012785 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012786 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012787 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012788 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012789 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012790 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12791 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012792 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012793 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012794 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012795 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012796 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012797 {}
12798};
12799
Takashi Iwaia9111322011-05-02 11:30:18 +020012800static const struct alc_config_preset alc262_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012801 [ALC262_BASIC] = {
12802 .mixers = { alc262_base_mixer },
12803 .init_verbs = { alc262_init_verbs },
12804 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12805 .dac_nids = alc262_dac_nids,
12806 .hp_nid = 0x03,
12807 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12808 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012809 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012810 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012811 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012812 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012813 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012814 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12815 .dac_nids = alc262_dac_nids,
12816 .hp_nid = 0x03,
12817 .dig_out_nid = ALC262_DIGOUT_NID,
12818 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12819 .channel_mode = alc262_modes,
12820 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012821 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012822 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012823 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012824 },
12825 [ALC262_HIPPO_1] = {
12826 .mixers = { alc262_hippo1_mixer },
12827 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12828 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12829 .dac_nids = alc262_dac_nids,
12830 .hp_nid = 0x02,
12831 .dig_out_nid = ALC262_DIGOUT_NID,
12832 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12833 .channel_mode = alc262_modes,
12834 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012835 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012836 .setup = alc262_hippo1_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012837 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012838 },
Takashi Iwai834be882006-03-01 14:16:17 +010012839 [ALC262_FUJITSU] = {
12840 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012841 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12842 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012843 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12844 .dac_nids = alc262_dac_nids,
12845 .hp_nid = 0x03,
12846 .dig_out_nid = ALC262_DIGOUT_NID,
12847 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12848 .channel_mode = alc262_modes,
12849 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012850 .unsol_event = alc_sku_unsol_event,
12851 .setup = alc262_fujitsu_setup,
12852 .init_hook = alc_inithook,
Takashi Iwai834be882006-03-01 14:16:17 +010012853 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012854 [ALC262_HP_BPC] = {
12855 .mixers = { alc262_HP_BPC_mixer },
12856 .init_verbs = { alc262_HP_BPC_init_verbs },
12857 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12858 .dac_nids = alc262_dac_nids,
12859 .hp_nid = 0x03,
12860 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12861 .channel_mode = alc262_modes,
12862 .input_mux = &alc262_HP_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012863 .unsol_event = alc_sku_unsol_event,
12864 .setup = alc262_hp_bpc_setup,
12865 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012866 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012867 [ALC262_HP_BPC_D7000_WF] = {
12868 .mixers = { alc262_HP_BPC_WildWest_mixer },
12869 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12870 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12871 .dac_nids = alc262_dac_nids,
12872 .hp_nid = 0x03,
12873 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12874 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012875 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012876 .unsol_event = alc_sku_unsol_event,
12877 .setup = alc262_hp_wildwest_setup,
12878 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012879 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012880 [ALC262_HP_BPC_D7000_WL] = {
12881 .mixers = { alc262_HP_BPC_WildWest_mixer,
12882 alc262_HP_BPC_WildWest_option_mixer },
12883 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12884 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12885 .dac_nids = alc262_dac_nids,
12886 .hp_nid = 0x03,
12887 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12888 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012889 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012890 .unsol_event = alc_sku_unsol_event,
12891 .setup = alc262_hp_wildwest_setup,
12892 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012893 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012894 [ALC262_HP_TC_T5735] = {
12895 .mixers = { alc262_hp_t5735_mixer },
12896 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12897 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12898 .dac_nids = alc262_dac_nids,
12899 .hp_nid = 0x03,
12900 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12901 .channel_mode = alc262_modes,
12902 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012903 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012904 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012905 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012906 },
12907 [ALC262_HP_RP5700] = {
12908 .mixers = { alc262_hp_rp5700_mixer },
12909 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12910 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12911 .dac_nids = alc262_dac_nids,
12912 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12913 .channel_mode = alc262_modes,
12914 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012915 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012916 [ALC262_BENQ_ED8] = {
12917 .mixers = { alc262_base_mixer },
12918 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12919 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12920 .dac_nids = alc262_dac_nids,
12921 .hp_nid = 0x03,
12922 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12923 .channel_mode = alc262_modes,
12924 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012925 },
Kailang Yang272a5272007-05-14 11:00:38 +020012926 [ALC262_SONY_ASSAMD] = {
12927 .mixers = { alc262_sony_mixer },
12928 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12929 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12930 .dac_nids = alc262_dac_nids,
12931 .hp_nid = 0x02,
12932 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12933 .channel_mode = alc262_modes,
12934 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012935 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012936 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012937 .init_hook = alc_inithook,
Kailang Yang83c34212007-07-05 11:43:05 +020012938 },
12939 [ALC262_BENQ_T31] = {
12940 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012941 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12942 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012943 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12944 .dac_nids = alc262_dac_nids,
12945 .hp_nid = 0x03,
12946 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12947 .channel_mode = alc262_modes,
12948 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012949 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012950 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012951 .init_hook = alc_inithook,
Kailang Yangea1fb292008-08-26 12:58:38 +020012952 },
Tobin Davisf651b502007-10-26 12:40:47 +020012953 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012954 .mixers = { alc262_ultra_mixer },
12955 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012956 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012957 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12958 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012959 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12960 .channel_mode = alc262_modes,
12961 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012962 .adc_nids = alc262_adc_nids, /* ADC0 */
12963 .capsrc_nids = alc262_capsrc_nids,
12964 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012965 .unsol_event = alc262_ultra_unsol_event,
12966 .init_hook = alc262_ultra_automute,
12967 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012968 [ALC262_LENOVO_3000] = {
12969 .mixers = { alc262_lenovo_3000_mixer },
12970 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012971 alc262_lenovo_3000_unsol_verbs,
12972 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012973 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12974 .dac_nids = alc262_dac_nids,
12975 .hp_nid = 0x03,
12976 .dig_out_nid = ALC262_DIGOUT_NID,
12977 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12978 .channel_mode = alc262_modes,
12979 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012980 .unsol_event = alc_sku_unsol_event,
12981 .setup = alc262_lenovo_3000_setup,
12982 .init_hook = alc_inithook,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012983 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012984 [ALC262_NEC] = {
12985 .mixers = { alc262_nec_mixer },
12986 .init_verbs = { alc262_nec_verbs },
12987 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12988 .dac_nids = alc262_dac_nids,
12989 .hp_nid = 0x03,
12990 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12991 .channel_mode = alc262_modes,
12992 .input_mux = &alc262_capture_source,
12993 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012994 [ALC262_TOSHIBA_S06] = {
12995 .mixers = { alc262_toshiba_s06_mixer },
12996 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12997 alc262_eapd_verbs },
12998 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12999 .capsrc_nids = alc262_dmic_capsrc_nids,
13000 .dac_nids = alc262_dac_nids,
13001 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020013002 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020013003 .dig_out_nid = ALC262_DIGOUT_NID,
13004 .num_channel_mode = ARRAY_SIZE(alc262_modes),
13005 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013006 .unsol_event = alc_sku_unsol_event,
13007 .setup = alc262_toshiba_s06_setup,
13008 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020013009 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020013010 [ALC262_TOSHIBA_RX1] = {
13011 .mixers = { alc262_toshiba_rx1_mixer },
13012 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
13013 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
13014 .dac_nids = alc262_dac_nids,
13015 .hp_nid = 0x03,
13016 .num_channel_mode = ARRAY_SIZE(alc262_modes),
13017 .channel_mode = alc262_modes,
13018 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013019 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013020 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013021 .init_hook = alc_inithook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020013022 },
Tony Vroonba340e82009-02-02 19:01:30 +000013023 [ALC262_TYAN] = {
13024 .mixers = { alc262_tyan_mixer },
13025 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
13026 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
13027 .dac_nids = alc262_dac_nids,
13028 .hp_nid = 0x02,
13029 .dig_out_nid = ALC262_DIGOUT_NID,
13030 .num_channel_mode = ARRAY_SIZE(alc262_modes),
13031 .channel_mode = alc262_modes,
13032 .input_mux = &alc262_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020013033 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013034 .setup = alc262_tyan_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020013035 .init_hook = alc_hp_automute,
Tony Vroonba340e82009-02-02 19:01:30 +000013036 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013037};
13038
13039static int patch_alc262(struct hda_codec *codec)
13040{
13041 struct alc_spec *spec;
13042 int board_config;
13043 int err;
13044
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013045 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013046 if (spec == NULL)
13047 return -ENOMEM;
13048
13049 codec->spec = spec;
13050#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013051 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
13052 * under-run
13053 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013054 {
13055 int tmp;
13056 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
13057 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
13058 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
13059 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
13060 }
13061#endif
Kailang Yangda00c242010-03-19 11:23:45 +010013062 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013063
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013064 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
13065
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013066 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
13067 alc262_models,
13068 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010013069
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013070 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013071 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13072 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010013073 board_config = ALC262_AUTO;
13074 }
13075
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010013076 if (board_config == ALC262_AUTO) {
13077 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
13078 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
13079 }
Takashi Iwai18675e42010-09-08 15:55:44 +020013080
Kailang Yangdf694da2005-12-05 19:42:22 +010013081 if (board_config == ALC262_AUTO) {
13082 /* automatic parse from the BIOS config */
13083 err = alc262_parse_auto_config(codec);
13084 if (err < 0) {
13085 alc_free(codec);
13086 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013087 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013088 printk(KERN_INFO
13089 "hda_codec: Cannot set up configuration "
13090 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013091 board_config = ALC262_BASIC;
13092 }
13093 }
13094
Takashi Iwaidc1eae22010-07-29 15:30:02 +020013095 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010013096 err = snd_hda_attach_beep_device(codec, 0x1);
13097 if (err < 0) {
13098 alc_free(codec);
13099 return err;
13100 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013101 }
13102
Kailang Yangdf694da2005-12-05 19:42:22 +010013103 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013104 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013105
Kailang Yangdf694da2005-12-05 19:42:22 +010013106 spec->stream_analog_playback = &alc262_pcm_analog_playback;
13107 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020013108
Kailang Yangdf694da2005-12-05 19:42:22 +010013109 spec->stream_digital_playback = &alc262_pcm_digital_playback;
13110 spec->stream_digital_capture = &alc262_pcm_digital_capture;
13111
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013112 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020013113 int i;
13114 /* check whether the digital-mic has to be supported */
13115 for (i = 0; i < spec->input_mux->num_items; i++) {
13116 if (spec->input_mux->items[i].index >= 9)
13117 break;
13118 }
13119 if (i < spec->input_mux->num_items) {
13120 /* use only ADC0 */
13121 spec->adc_nids = alc262_dmic_adc_nids;
13122 spec->num_adc_nids = 1;
13123 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010013124 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020013125 /* all analog inputs */
13126 /* check whether NID 0x07 is valid */
13127 unsigned int wcap = get_wcaps(codec, 0x07);
13128
13129 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013130 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020013131 if (wcap != AC_WID_AUD_IN) {
13132 spec->adc_nids = alc262_adc_nids_alt;
13133 spec->num_adc_nids =
13134 ARRAY_SIZE(alc262_adc_nids_alt);
13135 spec->capsrc_nids = alc262_capsrc_nids_alt;
13136 } else {
13137 spec->adc_nids = alc262_adc_nids;
13138 spec->num_adc_nids =
13139 ARRAY_SIZE(alc262_adc_nids);
13140 spec->capsrc_nids = alc262_capsrc_nids;
13141 }
Kailang Yangdf694da2005-12-05 19:42:22 +010013142 }
13143 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010013144 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013145 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020013146 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010013147 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010013148
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010013149 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020013150
Takashi Iwai2134ea42008-01-10 16:53:55 +010013151 spec->vmaster_nid = 0x0c;
13152
Kailang Yangdf694da2005-12-05 19:42:22 +010013153 codec->patch_ops = alc_patch_ops;
13154 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013155 spec->init_hook = alc262_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020013156 spec->shutup = alc_eapd_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020013157
13158 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020013159#ifdef CONFIG_SND_HDA_POWER_SAVE
13160 if (!spec->loopback.amplist)
13161 spec->loopback.amplist = alc262_loopbacks;
13162#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013163
Kailang Yangdf694da2005-12-05 19:42:22 +010013164 return 0;
13165}
13166
Kailang Yangdf694da2005-12-05 19:42:22 +010013167/*
Kailang Yanga361d842007-06-05 12:30:55 +020013168 * ALC268 channel source setting (2 channel)
13169 */
13170#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
13171#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020013172
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013173static const hda_nid_t alc268_dac_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013174 /* front, hp */
13175 0x02, 0x03
13176};
13177
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013178static const hda_nid_t alc268_adc_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013179 /* ADC0-1 */
13180 0x08, 0x07
13181};
13182
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013183static const hda_nid_t alc268_adc_nids_alt[1] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013184 /* ADC0 */
13185 0x08
13186};
13187
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013188static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
Takashi Iwaie1406342008-02-11 18:32:32 +010013189
Takashi Iwaia9111322011-05-02 11:30:18 +020013190static const struct snd_kcontrol_new alc268_base_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013191 /* output mixer control */
13192 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13193 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13194 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13195 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013196 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13197 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13198 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020013199 { }
13200};
13201
Takashi Iwaia9111322011-05-02 11:30:18 +020013202static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013203 /* output mixer control */
13204 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13205 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13206 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010013207 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13208 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13209 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020013210 { }
13211};
13212
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013213/* bind Beep switches of both NID 0x0f and 0x10 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013214static const struct hda_bind_ctls alc268_bind_beep_sw = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013215 .ops = &snd_hda_bind_sw,
13216 .values = {
13217 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
13218 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
13219 0
13220 },
13221};
13222
Takashi Iwaia9111322011-05-02 11:30:18 +020013223static const struct snd_kcontrol_new alc268_beep_mixer[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013224 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
13225 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
13226 { }
13227};
13228
Takashi Iwaia9111322011-05-02 11:30:18 +020013229static const struct hda_verb alc268_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020013230 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13231 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13232 { }
13233};
13234
Takashi Iwaid2738092007-08-16 14:59:45 +020013235/* Toshiba specific */
Takashi Iwaia9111322011-05-02 11:30:18 +020013236static const struct hda_verb alc268_toshiba_verbs[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020013237 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13238 { } /* end */
13239};
13240
13241/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020013242/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013243static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
Takashi Iwai6bc96852007-08-17 09:02:12 +020013244 .ops = &snd_hda_bind_vol,
13245 .values = {
13246 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
13247 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
13248 0
13249 },
13250};
13251
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013252static void alc268_acer_setup(struct hda_codec *codec)
Takashi Iwai889c4392007-08-23 18:56:52 +020013253{
13254 struct alc_spec *spec = codec->spec;
Takashi Iwai889c4392007-08-23 18:56:52 +020013255
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013256 spec->autocfg.hp_pins[0] = 0x14;
13257 spec->autocfg.speaker_pins[0] = 0x15;
13258 spec->automute = 1;
13259 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai889c4392007-08-23 18:56:52 +020013260}
13261
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013262#define alc268_acer_master_sw_get alc262_hp_master_sw_get
13263#define alc268_acer_master_sw_put alc262_hp_master_sw_put
Takashi Iwaid2738092007-08-16 14:59:45 +020013264
Takashi Iwaia9111322011-05-02 11:30:18 +020013265static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020013266 /* output mixer control */
13267 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13268 {
13269 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13270 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013271 .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
13272 .info = snd_ctl_boolean_mono_info,
13273 .get = alc268_acer_master_sw_get,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013274 .put = alc268_acer_master_sw_put,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013275 },
13276 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13277 { }
13278};
13279
Takashi Iwaia9111322011-05-02 11:30:18 +020013280static const struct snd_kcontrol_new alc268_acer_mixer[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020013281 /* output mixer control */
13282 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13283 {
13284 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13285 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013286 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
13287 .info = snd_ctl_boolean_mono_info,
13288 .get = alc268_acer_master_sw_get,
Takashi Iwaid2738092007-08-16 14:59:45 +020013289 .put = alc268_acer_master_sw_put,
Takashi Iwaid2738092007-08-16 14:59:45 +020013290 },
David Henningsson5f99f862011-01-04 15:24:24 +010013291 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13292 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
13293 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013294 { }
13295};
13296
Takashi Iwaia9111322011-05-02 11:30:18 +020013297static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013298 /* output mixer control */
13299 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13300 {
13301 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13302 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013303 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
13304 .info = snd_ctl_boolean_mono_info,
13305 .get = alc268_acer_master_sw_get,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013306 .put = alc268_acer_master_sw_put,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013307 },
David Henningsson5f99f862011-01-04 15:24:24 +010013308 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13309 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013310 { }
13311};
13312
Takashi Iwaia9111322011-05-02 11:30:18 +020013313static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020013314 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13315 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13316 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13317 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13318 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13319 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13320 { }
13321};
13322
Takashi Iwaia9111322011-05-02 11:30:18 +020013323static const struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013324 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13325 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013326 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13327 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013328 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13329 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013330 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13331 { }
13332};
13333
13334/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013335#define alc268_toshiba_setup alc262_hippo_setup
Takashi Iwaid2738092007-08-16 14:59:45 +020013336
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013337static void alc268_acer_lc_setup(struct hda_codec *codec)
13338{
13339 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013340 spec->autocfg.hp_pins[0] = 0x15;
13341 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013342 spec->automute = 1;
Takashi Iwai54463a62011-06-13 08:32:06 +020013343 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013344 spec->ext_mic.pin = 0x18;
13345 spec->ext_mic.mux_idx = 0;
13346 spec->int_mic.pin = 0x12;
13347 spec->int_mic.mux_idx = 6;
13348 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013349}
13350
Takashi Iwaia9111322011-05-02 11:30:18 +020013351static const struct snd_kcontrol_new alc268_dell_mixer[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013352 /* output mixer control */
13353 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13354 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13355 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13356 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013357 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13358 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013359 { }
13360};
13361
Takashi Iwaia9111322011-05-02 11:30:18 +020013362static const struct hda_verb alc268_dell_verbs[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013363 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13364 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13365 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013366 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013367 { }
13368};
13369
13370/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013371static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013372{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013373 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013374
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013375 spec->autocfg.hp_pins[0] = 0x15;
13376 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013377 spec->ext_mic.pin = 0x18;
13378 spec->ext_mic.mux_idx = 0;
13379 spec->int_mic.pin = 0x19;
13380 spec->int_mic.mux_idx = 1;
13381 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020013382 spec->automute = 1;
13383 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013384}
13385
Takashi Iwaia9111322011-05-02 11:30:18 +020013386static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013387 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13388 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13389 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13390 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13391 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13392 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013393 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13394 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013395 { }
13396};
13397
Takashi Iwaia9111322011-05-02 11:30:18 +020013398static const struct hda_verb alc267_quanta_il1_verbs[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013399 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13400 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13401 { }
13402};
13403
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013404static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013405{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013406 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013407 spec->autocfg.hp_pins[0] = 0x15;
13408 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013409 spec->ext_mic.pin = 0x18;
13410 spec->ext_mic.mux_idx = 0;
13411 spec->int_mic.pin = 0x19;
13412 spec->int_mic.mux_idx = 1;
13413 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020013414 spec->automute = 1;
13415 spec->automute_mode = ALC_AUTOMUTE_PIN;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013416}
13417
Kailang Yanga361d842007-06-05 12:30:55 +020013418/*
13419 * generic initialization of ADC, input mixers and output mixers
13420 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013421static const struct hda_verb alc268_base_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013422 /* Unmute DAC0-1 and set vol = 0 */
13423 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013424 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013425
13426 /*
13427 * Set up output mixers (0x0c - 0x0e)
13428 */
13429 /* set vol=0 to output mixers */
13430 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013431 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13432
13433 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13434 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13435
13436 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13437 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13438 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13439 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13440 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13441 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13442 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13443 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13444
13445 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13446 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13447 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13448 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013449 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013450
13451 /* set PCBEEP vol = 0, mute connections */
13452 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13453 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13454 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013455
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013456 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013457
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013458 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13459 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13460 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13461 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013462
Kailang Yanga361d842007-06-05 12:30:55 +020013463 { }
13464};
13465
13466/*
13467 * generic initialization of ADC, input mixers and output mixers
13468 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013469static const struct hda_verb alc268_volume_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013470 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013471 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13472 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013473
13474 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13475 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13476 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13477 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13478 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13479
Kailang Yanga361d842007-06-05 12:30:55 +020013480 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013481 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13482 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13483
13484 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013485 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013486
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013487 /* set PCBEEP vol = 0, mute connections */
13488 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13489 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13490 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013491
13492 { }
13493};
13494
Takashi Iwaia9111322011-05-02 11:30:18 +020013495static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013496 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13497 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13498 { } /* end */
13499};
13500
Takashi Iwaia9111322011-05-02 11:30:18 +020013501static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013502 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13503 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013504 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013505 { } /* end */
13506};
13507
Takashi Iwaia9111322011-05-02 11:30:18 +020013508static const struct snd_kcontrol_new alc268_capture_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013509 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13510 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13511 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13512 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013513 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013514 { } /* end */
13515};
13516
Takashi Iwaia9111322011-05-02 11:30:18 +020013517static const struct hda_input_mux alc268_capture_source = {
Kailang Yanga361d842007-06-05 12:30:55 +020013518 .num_items = 4,
13519 .items = {
13520 { "Mic", 0x0 },
13521 { "Front Mic", 0x1 },
13522 { "Line", 0x2 },
13523 { "CD", 0x3 },
13524 },
13525};
13526
Takashi Iwaia9111322011-05-02 11:30:18 +020013527static const struct hda_input_mux alc268_acer_capture_source = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013528 .num_items = 3,
13529 .items = {
13530 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013531 { "Internal Mic", 0x1 },
13532 { "Line", 0x2 },
13533 },
13534};
13535
Takashi Iwaia9111322011-05-02 11:30:18 +020013536static const struct hda_input_mux alc268_acer_dmic_capture_source = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013537 .num_items = 3,
13538 .items = {
13539 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013540 { "Internal Mic", 0x6 },
13541 { "Line", 0x2 },
13542 },
13543};
13544
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013545#ifdef CONFIG_SND_DEBUG
Takashi Iwaia9111322011-05-02 11:30:18 +020013546static const struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013547 /* Volume widgets */
13548 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13549 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13550 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13551 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13552 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13553 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13554 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13555 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13556 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13557 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13558 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13559 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13560 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013561 /* The below appears problematic on some hardwares */
13562 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013563 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13564 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13565 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13566 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13567
13568 /* Modes for retasking pin widgets */
13569 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13570 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13571 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13572 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13573
13574 /* Controls for GPIO pins, assuming they are configured as outputs */
13575 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13576 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13577 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13578 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13579
13580 /* Switches to allow the digital SPDIF output pin to be enabled.
13581 * The ALC268 does not have an SPDIF input.
13582 */
13583 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13584
13585 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13586 * this output to turn on an external amplifier.
13587 */
13588 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13589 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13590
13591 { } /* end */
13592};
13593#endif
13594
Kailang Yanga361d842007-06-05 12:30:55 +020013595/* create input playback/capture controls for the given pin */
13596static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13597 const char *ctlname, int idx)
13598{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013599 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013600 int err;
13601
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013602 switch (nid) {
13603 case 0x14:
13604 case 0x16:
13605 dac = 0x02;
13606 break;
13607 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013608 case 0x1a: /* ALC259/269 only */
13609 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013610 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013611 dac = 0x03;
13612 break;
13613 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013614 snd_printd(KERN_WARNING "hda_codec: "
13615 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013616 return 0;
13617 }
13618 if (spec->multiout.dac_nids[0] != dac &&
13619 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013620 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013621 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013622 HDA_OUTPUT));
13623 if (err < 0)
13624 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020013625 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013626 }
13627
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013628 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013629 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013630 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013631 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013632 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013633 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013634 if (err < 0)
13635 return err;
13636 return 0;
13637}
13638
13639/* add playback controls from the parsed DAC table */
13640static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13641 const struct auto_pin_cfg *cfg)
13642{
13643 hda_nid_t nid;
13644 int err;
13645
Kailang Yanga361d842007-06-05 12:30:55 +020013646 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013647
13648 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013649 if (nid) {
13650 const char *name;
13651 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13652 name = "Speaker";
13653 else
13654 name = "Front";
13655 err = alc268_new_analog_output(spec, nid, name, 0);
13656 if (err < 0)
13657 return err;
13658 }
Kailang Yanga361d842007-06-05 12:30:55 +020013659
13660 nid = cfg->speaker_pins[0];
13661 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013662 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013663 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13664 if (err < 0)
13665 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013666 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013667 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13668 if (err < 0)
13669 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013670 }
13671 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013672 if (nid) {
13673 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13674 if (err < 0)
13675 return err;
13676 }
Kailang Yanga361d842007-06-05 12:30:55 +020013677
13678 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13679 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013680 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013681 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013682 if (err < 0)
13683 return err;
13684 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013685 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013686}
13687
13688/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013689static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013690 const struct auto_pin_cfg *cfg)
13691{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013692 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013693}
13694
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013695static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13696 hda_nid_t nid, int pin_type)
13697{
13698 int idx;
13699
13700 alc_set_pin_output(codec, nid, pin_type);
13701 if (nid == 0x14 || nid == 0x16)
13702 idx = 0;
13703 else
13704 idx = 1;
13705 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13706}
13707
13708static void alc268_auto_init_multi_out(struct hda_codec *codec)
13709{
13710 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013711 int i;
13712
13713 for (i = 0; i < spec->autocfg.line_outs; i++) {
13714 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013715 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13716 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13717 }
13718}
13719
13720static void alc268_auto_init_hp_out(struct hda_codec *codec)
13721{
13722 struct alc_spec *spec = codec->spec;
13723 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013724 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013725
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013726 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13727 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013728 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013729 }
13730 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13731 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013732 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013733 }
13734 if (spec->autocfg.mono_out_pin)
13735 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13736 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013737}
13738
Kailang Yanga361d842007-06-05 12:30:55 +020013739static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13740{
13741 struct alc_spec *spec = codec->spec;
13742 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13743 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13744 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13745 unsigned int dac_vol1, dac_vol2;
13746
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013747 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013748 snd_hda_codec_write(codec, speaker_nid, 0,
13749 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013750 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013751 snd_hda_codec_write(codec, 0x0f, 0,
13752 AC_VERB_SET_AMP_GAIN_MUTE,
13753 AMP_IN_UNMUTE(1));
13754 snd_hda_codec_write(codec, 0x10, 0,
13755 AC_VERB_SET_AMP_GAIN_MUTE,
13756 AMP_IN_UNMUTE(1));
13757 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013758 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013759 snd_hda_codec_write(codec, 0x0f, 0,
13760 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13761 snd_hda_codec_write(codec, 0x10, 0,
13762 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13763 }
13764
13765 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013766 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013767 dac_vol2 = AMP_OUT_ZERO;
13768 else if (line_nid == 0x15)
13769 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013770 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013771 dac_vol2 = AMP_OUT_ZERO;
13772 else if (hp_nid == 0x15)
13773 dac_vol1 = AMP_OUT_ZERO;
13774 if (line_nid != 0x16 || hp_nid != 0x16 ||
13775 spec->autocfg.line_out_pins[1] != 0x16 ||
13776 spec->autocfg.line_out_pins[2] != 0x16)
13777 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13778
13779 snd_hda_codec_write(codec, 0x02, 0,
13780 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13781 snd_hda_codec_write(codec, 0x03, 0,
13782 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13783}
13784
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013785/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013786#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13787#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013788#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013789#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13790
13791/*
13792 * BIOS auto configuration
13793 */
13794static int alc268_parse_auto_config(struct hda_codec *codec)
13795{
13796 struct alc_spec *spec = codec->spec;
13797 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013798 static const hda_nid_t alc268_ignore[] = { 0 };
Kailang Yanga361d842007-06-05 12:30:55 +020013799
13800 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13801 alc268_ignore);
13802 if (err < 0)
13803 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013804 if (!spec->autocfg.line_outs) {
13805 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13806 spec->multiout.max_channels = 2;
13807 spec->no_analog = 1;
13808 goto dig_only;
13809 }
Kailang Yanga361d842007-06-05 12:30:55 +020013810 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013811 }
Kailang Yanga361d842007-06-05 12:30:55 +020013812 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13813 if (err < 0)
13814 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013815 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013816 if (err < 0)
13817 return err;
13818
13819 spec->multiout.max_channels = 2;
13820
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013821 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013822 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013823 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013824 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013825 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013826
Takashi Iwai892981f2009-03-02 08:04:35 +010013827 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013828 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013829
Takashi Iwaid88897e2008-10-31 15:01:37 +010013830 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013831 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013832 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013833
Takashi Iwai776e1842007-08-29 15:07:11 +020013834 err = alc_auto_add_mic_boost(codec);
13835 if (err < 0)
13836 return err;
13837
Kailang Yang6227cdc2010-02-25 08:36:52 +010013838 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013839
Kailang Yanga361d842007-06-05 12:30:55 +020013840 return 1;
13841}
13842
Kailang Yanga361d842007-06-05 12:30:55 +020013843#define alc268_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010013844#define alc268_auto_init_input_src alc882_auto_init_input_src
Kailang Yanga361d842007-06-05 12:30:55 +020013845
13846/* init callback for auto-configuration model -- overriding the default init */
13847static void alc268_auto_init(struct hda_codec *codec)
13848{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013849 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013850 alc268_auto_init_multi_out(codec);
13851 alc268_auto_init_hp_out(codec);
13852 alc268_auto_init_mono_speaker_out(codec);
13853 alc268_auto_init_analog_input(codec);
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010013854 alc268_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013855 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013856 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013857 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013858}
13859
13860/*
13861 * configuration and preset
13862 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013863static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013864 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013865 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013866 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013867 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013868 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013869 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013870 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013871 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013872#ifdef CONFIG_SND_DEBUG
13873 [ALC268_TEST] = "test",
13874#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013875 [ALC268_AUTO] = "auto",
13876};
13877
Takashi Iwaia9111322011-05-02 11:30:18 +020013878static const struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013879 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013880 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013881 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013882 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013883 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013884 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13885 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013886 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chen0a1896b2011-06-06 18:55:34 -040013887 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013888 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13889 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013890 /* almost compatible with toshiba but with optional digital outs;
13891 * auto-probing seems working fine
13892 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013893 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013894 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013895 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013896 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013897 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013898 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013899 {}
13900};
13901
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013902/* Toshiba laptops have no unique PCI SSID but only codec SSID */
Takashi Iwaia9111322011-05-02 11:30:18 +020013903static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013904 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13905 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13906 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13907 ALC268_TOSHIBA),
13908 {}
13909};
13910
Takashi Iwaia9111322011-05-02 11:30:18 +020013911static const struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013912 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013913 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13914 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013915 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13916 alc267_quanta_il1_verbs },
13917 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13918 .dac_nids = alc268_dac_nids,
13919 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13920 .adc_nids = alc268_adc_nids_alt,
13921 .hp_nid = 0x03,
13922 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13923 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013924 .unsol_event = alc_sku_unsol_event,
13925 .setup = alc267_quanta_il1_setup,
13926 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013927 },
Kailang Yanga361d842007-06-05 12:30:55 +020013928 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013929 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13930 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013931 .init_verbs = { alc268_base_init_verbs },
13932 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13933 .dac_nids = alc268_dac_nids,
13934 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13935 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013936 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013937 .hp_nid = 0x03,
13938 .dig_out_nid = ALC268_DIGOUT_NID,
13939 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13940 .channel_mode = alc268_modes,
13941 .input_mux = &alc268_capture_source,
13942 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013943 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013944 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013945 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013946 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13947 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013948 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13949 .dac_nids = alc268_dac_nids,
13950 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13951 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013952 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013953 .hp_nid = 0x03,
13954 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13955 .channel_mode = alc268_modes,
13956 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013957 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013958 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013959 .init_hook = alc_inithook,
Takashi Iwaid2738092007-08-16 14:59:45 +020013960 },
13961 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013962 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013963 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013964 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13965 alc268_acer_verbs },
13966 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13967 .dac_nids = alc268_dac_nids,
13968 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13969 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013970 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013971 .hp_nid = 0x02,
13972 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13973 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013974 .input_mux = &alc268_acer_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013975 .unsol_event = alc_sku_unsol_event,
13976 .setup = alc268_acer_setup,
13977 .init_hook = alc_inithook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013978 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013979 [ALC268_ACER_DMIC] = {
13980 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13981 alc268_beep_mixer },
13982 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13983 alc268_acer_verbs },
13984 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13985 .dac_nids = alc268_dac_nids,
13986 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13987 .adc_nids = alc268_adc_nids_alt,
13988 .capsrc_nids = alc268_capsrc_nids,
13989 .hp_nid = 0x02,
13990 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13991 .channel_mode = alc268_modes,
13992 .input_mux = &alc268_acer_dmic_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013993 .unsol_event = alc_sku_unsol_event,
13994 .setup = alc268_acer_setup,
13995 .init_hook = alc_inithook,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013996 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013997 [ALC268_ACER_ASPIRE_ONE] = {
13998 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013999 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014000 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020014001 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14002 alc268_acer_aspire_one_verbs },
14003 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14004 .dac_nids = alc268_dac_nids,
14005 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14006 .adc_nids = alc268_adc_nids_alt,
14007 .capsrc_nids = alc268_capsrc_nids,
14008 .hp_nid = 0x03,
14009 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14010 .channel_mode = alc268_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014011 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014012 .setup = alc268_acer_lc_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014013 .init_hook = alc_inithook,
Kailang Yang8ef355d2008-08-26 13:10:22 +020014014 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014015 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014016 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
14017 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014018 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14019 alc268_dell_verbs },
14020 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14021 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014022 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14023 .adc_nids = alc268_adc_nids_alt,
14024 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014025 .hp_nid = 0x02,
14026 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14027 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014028 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014029 .setup = alc268_dell_setup,
14030 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014031 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014032 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014033 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
14034 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014035 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14036 alc268_toshiba_verbs },
14037 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14038 .dac_nids = alc268_dac_nids,
14039 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14040 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010014041 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014042 .hp_nid = 0x03,
14043 .dig_out_nid = ALC268_DIGOUT_NID,
14044 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14045 .channel_mode = alc268_modes,
14046 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020014047 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014048 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020014049 .init_hook = alc_inithook,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014050 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010014051#ifdef CONFIG_SND_DEBUG
14052 [ALC268_TEST] = {
14053 .mixers = { alc268_test_mixer, alc268_capture_mixer },
14054 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14055 alc268_volume_init_verbs },
14056 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14057 .dac_nids = alc268_dac_nids,
14058 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14059 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010014060 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010014061 .hp_nid = 0x03,
14062 .dig_out_nid = ALC268_DIGOUT_NID,
14063 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14064 .channel_mode = alc268_modes,
14065 .input_mux = &alc268_capture_source,
14066 },
14067#endif
Kailang Yanga361d842007-06-05 12:30:55 +020014068};
14069
14070static int patch_alc268(struct hda_codec *codec)
14071{
14072 struct alc_spec *spec;
14073 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010014074 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020014075
Julia Lawallef86f582009-12-19 08:18:03 +010014076 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020014077 if (spec == NULL)
14078 return -ENOMEM;
14079
14080 codec->spec = spec;
14081
14082 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
14083 alc268_models,
14084 alc268_cfg_tbl);
14085
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014086 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
14087 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010014088 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014089
Kailang Yanga361d842007-06-05 12:30:55 +020014090 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014091 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14092 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020014093 board_config = ALC268_AUTO;
14094 }
14095
14096 if (board_config == ALC268_AUTO) {
14097 /* automatic parse from the BIOS config */
14098 err = alc268_parse_auto_config(codec);
14099 if (err < 0) {
14100 alc_free(codec);
14101 return err;
14102 } else if (!err) {
14103 printk(KERN_INFO
14104 "hda_codec: Cannot set up configuration "
14105 "from BIOS. Using base mode...\n");
14106 board_config = ALC268_3ST;
14107 }
14108 }
14109
14110 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014111 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020014112
Kailang Yanga361d842007-06-05 12:30:55 +020014113 spec->stream_analog_playback = &alc268_pcm_analog_playback;
14114 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010014115 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020014116
Kailang Yanga361d842007-06-05 12:30:55 +020014117 spec->stream_digital_playback = &alc268_pcm_digital_playback;
14118
Takashi Iwai22971e32009-02-10 11:56:44 +010014119 has_beep = 0;
14120 for (i = 0; i < spec->num_mixers; i++) {
14121 if (spec->mixers[i] == alc268_beep_mixer) {
14122 has_beep = 1;
14123 break;
14124 }
14125 }
14126
14127 if (has_beep) {
14128 err = snd_hda_attach_beep_device(codec, 0x1);
14129 if (err < 0) {
14130 alc_free(codec);
14131 return err;
14132 }
14133 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
14134 /* override the amp caps for beep generator */
14135 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014136 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
14137 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
14138 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
14139 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010014140 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014141
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014142 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014143 /* check whether NID 0x07 is valid */
14144 unsigned int wcap = get_wcaps(codec, 0x07);
Kailang Yanga361d842007-06-05 12:30:55 +020014145
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014146 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014147 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020014148 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014149 if (spec->auto_mic ||
14150 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014151 spec->adc_nids = alc268_adc_nids_alt;
14152 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014153 if (spec->auto_mic)
14154 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014155 if (spec->auto_mic || spec->input_mux->num_items == 1)
14156 add_mixer(spec, alc268_capture_nosrc_mixer);
14157 else
14158 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014159 } else {
14160 spec->adc_nids = alc268_adc_nids;
14161 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010014162 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020014163 }
14164 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010014165
14166 spec->vmaster_nid = 0x02;
14167
Kailang Yanga361d842007-06-05 12:30:55 +020014168 codec->patch_ops = alc_patch_ops;
14169 if (board_config == ALC268_AUTO)
14170 spec->init_hook = alc268_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020014171 spec->shutup = alc_eapd_shutup;
Kailang Yangea1fb292008-08-26 12:58:38 +020014172
Kailang Yangbf1b0222010-10-21 08:49:56 +020014173 alc_init_jacks(codec);
14174
Kailang Yanga361d842007-06-05 12:30:55 +020014175 return 0;
14176}
14177
14178/*
Kailang Yangf6a92242007-12-13 16:52:54 +010014179 * ALC269 channel source setting (2 channel)
14180 */
14181#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
14182
14183#define alc269_dac_nids alc260_dac_nids
14184
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014185static const hda_nid_t alc269_adc_nids[1] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014186 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020014187 0x08,
14188};
14189
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014190static const hda_nid_t alc269_capsrc_nids[1] = {
Takashi Iwaie01bf502008-08-21 16:25:07 +020014191 0x23,
14192};
14193
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014194static const hda_nid_t alc269vb_adc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014195 /* ADC1 */
14196 0x09,
14197};
14198
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014199static const hda_nid_t alc269vb_capsrc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014200 0x22,
14201};
14202
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014203static const hda_nid_t alc269_adc_candidates[] = {
David Henningsson262ac222011-04-07 11:43:00 +020014204 0x08, 0x09, 0x07, 0x11,
Takashi Iwai66946352010-03-29 17:21:45 +020014205};
Takashi Iwaie01bf502008-08-21 16:25:07 +020014206
Kailang Yangf6a92242007-12-13 16:52:54 +010014207#define alc269_modes alc260_modes
14208#define alc269_capture_source alc880_lg_lw_capture_source
14209
Takashi Iwaia9111322011-05-02 11:30:18 +020014210static const struct snd_kcontrol_new alc269_base_mixer[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014211 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14212 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14213 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14214 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14215 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14216 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014217 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014218 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14219 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014220 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014221 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14222 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
14223 { } /* end */
14224};
14225
Takashi Iwaia9111322011-05-02 11:30:18 +020014226static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014227 /* output mixer control */
14228 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14229 {
14230 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14231 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014232 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014233 .info = snd_hda_mixer_amp_switch_info,
14234 .get = snd_hda_mixer_amp_switch_get,
14235 .put = alc268_acer_master_sw_put,
14236 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14237 },
14238 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14239 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014240 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014241 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14242 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014243 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014244 { }
14245};
14246
Takashi Iwaia9111322011-05-02 11:30:18 +020014247static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
Tony Vroon64154832008-11-06 15:08:49 +000014248 /* output mixer control */
14249 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14250 {
14251 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14252 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014253 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014254 .info = snd_hda_mixer_amp_switch_info,
14255 .get = snd_hda_mixer_amp_switch_get,
14256 .put = alc268_acer_master_sw_put,
14257 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14258 },
14259 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14260 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014261 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014262 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14263 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014264 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014265 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14266 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014267 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014268 { }
14269};
14270
Takashi Iwaia9111322011-05-02 11:30:18 +020014271static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014272 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014273 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014274 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014275 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014276 { } /* end */
14277};
14278
Takashi Iwaia9111322011-05-02 11:30:18 +020014279static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014280 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14281 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14282 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14283 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14284 { } /* end */
14285};
14286
Takashi Iwaia9111322011-05-02 11:30:18 +020014287static const struct snd_kcontrol_new alc269_asus_mixer[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014288 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14289 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14290 { } /* end */
14291};
14292
Kailang Yangf6a92242007-12-13 16:52:54 +010014293/* capture mixer elements */
Takashi Iwaia9111322011-05-02 11:30:18 +020014294static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014295 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14296 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014297 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14298 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014299 { } /* end */
14300};
14301
Takashi Iwaia9111322011-05-02 11:30:18 +020014302static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014303 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14304 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014305 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014306 { } /* end */
14307};
14308
Takashi Iwaia9111322011-05-02 11:30:18 +020014309static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014310 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14311 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014312 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14313 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014314 { } /* end */
14315};
14316
Takashi Iwaia9111322011-05-02 11:30:18 +020014317static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014318 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14319 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014320 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014321 { } /* end */
14322};
14323
Takashi Iwai26f5df22008-11-03 17:39:46 +010014324/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014325#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014326
Takashi Iwaia9111322011-05-02 11:30:18 +020014327static const struct hda_verb alc269_quanta_fl1_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014328 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14329 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14330 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14331 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14332 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14333 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14334 { }
14335};
14336
Takashi Iwaia9111322011-05-02 11:30:18 +020014337static const struct hda_verb alc269_lifebook_verbs[] = {
Tony Vroon64154832008-11-06 15:08:49 +000014338 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14339 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14340 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14341 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14342 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14343 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14344 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14345 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14346 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14347 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14348 { }
14349};
14350
Kailang Yang60db6b52008-08-26 13:13:00 +020014351/* toggle speaker-output according to the hp-jack state */
14352static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14353{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014354 alc_hp_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014355
14356 snd_hda_codec_write(codec, 0x20, 0,
14357 AC_VERB_SET_COEF_INDEX, 0x0c);
14358 snd_hda_codec_write(codec, 0x20, 0,
14359 AC_VERB_SET_PROC_COEF, 0x680);
14360
14361 snd_hda_codec_write(codec, 0x20, 0,
14362 AC_VERB_SET_COEF_INDEX, 0x0c);
14363 snd_hda_codec_write(codec, 0x20, 0,
14364 AC_VERB_SET_PROC_COEF, 0x480);
14365}
14366
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014367#define alc269_lifebook_speaker_automute \
14368 alc269_quanta_fl1_speaker_automute
Tony Vroon64154832008-11-06 15:08:49 +000014369
Tony Vroon64154832008-11-06 15:08:49 +000014370static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14371{
14372 unsigned int present_laptop;
14373 unsigned int present_dock;
14374
Wu Fengguang864f92b2009-11-18 12:38:02 +080014375 present_laptop = snd_hda_jack_detect(codec, 0x18);
14376 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014377
14378 /* Laptop mic port overrides dock mic port, design decision */
14379 if (present_dock)
14380 snd_hda_codec_write(codec, 0x23, 0,
14381 AC_VERB_SET_CONNECT_SEL, 0x3);
14382 if (present_laptop)
14383 snd_hda_codec_write(codec, 0x23, 0,
14384 AC_VERB_SET_CONNECT_SEL, 0x0);
14385 if (!present_dock && !present_laptop)
14386 snd_hda_codec_write(codec, 0x23, 0,
14387 AC_VERB_SET_CONNECT_SEL, 0x1);
14388}
14389
Kailang Yang60db6b52008-08-26 13:13:00 +020014390static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14391 unsigned int res)
14392{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014393 switch (res >> 26) {
14394 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014395 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014396 break;
14397 case ALC880_MIC_EVENT:
14398 alc_mic_automute(codec);
14399 break;
14400 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014401}
14402
Tony Vroon64154832008-11-06 15:08:49 +000014403static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14404 unsigned int res)
14405{
14406 if ((res >> 26) == ALC880_HP_EVENT)
14407 alc269_lifebook_speaker_automute(codec);
14408 if ((res >> 26) == ALC880_MIC_EVENT)
14409 alc269_lifebook_mic_autoswitch(codec);
14410}
14411
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014412static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14413{
14414 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014415 spec->autocfg.hp_pins[0] = 0x15;
14416 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014417 spec->automute_mixer_nid[0] = 0x0c;
14418 spec->automute = 1;
14419 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014420 spec->ext_mic.pin = 0x18;
14421 spec->ext_mic.mux_idx = 0;
14422 spec->int_mic.pin = 0x19;
14423 spec->int_mic.mux_idx = 1;
14424 spec->auto_mic = 1;
14425}
14426
Kailang Yang60db6b52008-08-26 13:13:00 +020014427static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14428{
14429 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014430 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014431}
14432
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014433static void alc269_lifebook_setup(struct hda_codec *codec)
14434{
14435 struct alc_spec *spec = codec->spec;
14436 spec->autocfg.hp_pins[0] = 0x15;
14437 spec->autocfg.hp_pins[1] = 0x1a;
14438 spec->autocfg.speaker_pins[0] = 0x14;
14439 spec->automute_mixer_nid[0] = 0x0c;
14440 spec->automute = 1;
14441 spec->automute_mode = ALC_AUTOMUTE_MIXER;
14442}
14443
Tony Vroon64154832008-11-06 15:08:49 +000014444static void alc269_lifebook_init_hook(struct hda_codec *codec)
14445{
14446 alc269_lifebook_speaker_automute(codec);
14447 alc269_lifebook_mic_autoswitch(codec);
14448}
14449
Takashi Iwaia9111322011-05-02 11:30:18 +020014450static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014451 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14452 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14453 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14454 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14455 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14456 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14457 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14458 {}
14459};
14460
Takashi Iwaia9111322011-05-02 11:30:18 +020014461static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014462 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14463 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14464 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14465 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14466 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14467 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14468 {}
14469};
14470
Takashi Iwaia9111322011-05-02 11:30:18 +020014471static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014472 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14473 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14474 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14475 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14476 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14477 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14478 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14479 {}
14480};
14481
Takashi Iwaia9111322011-05-02 11:30:18 +020014482static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014483 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14484 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14485 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14486 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14487 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14488 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14489 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14490 {}
14491};
14492
Takashi Iwaia9111322011-05-02 11:30:18 +020014493static const struct hda_verb alc271_acer_dmic_verbs[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014494 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14495 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14496 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14497 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14498 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14499 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14500 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14501 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14502 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14503 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14504 { }
14505};
14506
Kailang Yang226b1ec2010-04-09 11:01:20 +020014507static void alc269_laptop_amic_setup(struct hda_codec *codec)
14508{
14509 struct alc_spec *spec = codec->spec;
14510 spec->autocfg.hp_pins[0] = 0x15;
14511 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014512 spec->automute_mixer_nid[0] = 0x0c;
14513 spec->automute = 1;
14514 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014515 spec->ext_mic.pin = 0x18;
14516 spec->ext_mic.mux_idx = 0;
14517 spec->int_mic.pin = 0x19;
14518 spec->int_mic.mux_idx = 1;
14519 spec->auto_mic = 1;
14520}
14521
Kailang Yang84898e82010-02-04 14:16:14 +010014522static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014523{
14524 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014525 spec->autocfg.hp_pins[0] = 0x15;
14526 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014527 spec->automute_mixer_nid[0] = 0x0c;
14528 spec->automute = 1;
14529 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014530 spec->ext_mic.pin = 0x18;
14531 spec->ext_mic.mux_idx = 0;
14532 spec->int_mic.pin = 0x12;
14533 spec->int_mic.mux_idx = 5;
14534 spec->auto_mic = 1;
14535}
14536
Kailang Yang226b1ec2010-04-09 11:01:20 +020014537static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014538{
14539 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014540 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014541 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014542 spec->automute_mixer_nid[0] = 0x0c;
14543 spec->automute = 1;
14544 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014545 spec->ext_mic.pin = 0x18;
14546 spec->ext_mic.mux_idx = 0;
14547 spec->int_mic.pin = 0x19;
14548 spec->int_mic.mux_idx = 1;
14549 spec->auto_mic = 1;
14550}
14551
Kailang Yang226b1ec2010-04-09 11:01:20 +020014552static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14553{
14554 struct alc_spec *spec = codec->spec;
14555 spec->autocfg.hp_pins[0] = 0x21;
14556 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014557 spec->automute_mixer_nid[0] = 0x0c;
14558 spec->automute = 1;
14559 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014560 spec->ext_mic.pin = 0x18;
14561 spec->ext_mic.mux_idx = 0;
14562 spec->int_mic.pin = 0x12;
14563 spec->int_mic.mux_idx = 6;
14564 spec->auto_mic = 1;
14565}
14566
Kailang Yangf6a92242007-12-13 16:52:54 +010014567/*
14568 * generic initialization of ADC, input mixers and output mixers
14569 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014570static const struct hda_verb alc269_init_verbs[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014571 /*
14572 * Unmute ADC0 and set the default input to mic-in
14573 */
Kailang Yang84898e82010-02-04 14:16:14 +010014574 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014575
14576 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014577 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014578 */
14579 /* set vol=0 to output mixers */
14580 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14581 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14582
14583 /* set up input amps for analog loopback */
14584 /* Amp Indices: DAC = 0, mixer = 1 */
14585 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14586 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14587 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14588 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14589 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14590 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14591
14592 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14593 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14594 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14595 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14596 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14597 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14598 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14599
14600 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14601 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014602
Kailang Yang84898e82010-02-04 14:16:14 +010014603 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014604 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14605 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014606 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014607
14608 /* set EAPD */
14609 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014610 { }
14611};
14612
Takashi Iwaia9111322011-05-02 11:30:18 +020014613static const struct hda_verb alc269vb_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014614 /*
14615 * Unmute ADC0 and set the default input to mic-in
14616 */
14617 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14618
14619 /*
14620 * Set up output mixers (0x02 - 0x03)
14621 */
14622 /* set vol=0 to output mixers */
14623 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14624 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14625
14626 /* set up input amps for analog loopback */
14627 /* Amp Indices: DAC = 0, mixer = 1 */
14628 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14629 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14630 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14631 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14632 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14633 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14634
14635 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14636 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14637 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14638 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14639 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14640 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14641 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14642
14643 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14644 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14645
14646 /* FIXME: use Mux-type input source selection */
14647 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14648 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14649 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14650
14651 /* set EAPD */
14652 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014653 { }
14654};
14655
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014656#define alc269_auto_create_multi_out_ctls \
14657 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014658#define alc269_auto_create_input_ctls \
14659 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014660
14661#ifdef CONFIG_SND_HDA_POWER_SAVE
14662#define alc269_loopbacks alc880_loopbacks
14663#endif
14664
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014665/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014666#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14667#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14668#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14669#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14670
Takashi Iwaia9111322011-05-02 11:30:18 +020014671static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014672 .substreams = 1,
14673 .channels_min = 2,
14674 .channels_max = 8,
14675 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14676 /* NID is set in alc_build_pcms */
14677 .ops = {
14678 .open = alc880_playback_pcm_open,
14679 .prepare = alc880_playback_pcm_prepare,
14680 .cleanup = alc880_playback_pcm_cleanup
14681 },
14682};
14683
Takashi Iwaia9111322011-05-02 11:30:18 +020014684static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014685 .substreams = 1,
14686 .channels_min = 2,
14687 .channels_max = 2,
14688 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14689 /* NID is set in alc_build_pcms */
14690};
14691
Takashi Iwaiad358792010-03-30 18:00:59 +020014692#ifdef CONFIG_SND_HDA_POWER_SAVE
14693static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14694{
14695 switch (codec->subsystem_id) {
14696 case 0x103c1586:
14697 return 1;
14698 }
14699 return 0;
14700}
14701
14702static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14703{
14704 /* update mute-LED according to the speaker mute state */
14705 if (nid == 0x01 || nid == 0x14) {
14706 int pinval;
14707 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14708 HDA_AMP_MUTE)
14709 pinval = 0x24;
14710 else
14711 pinval = 0x20;
14712 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014713 snd_hda_codec_update_cache(codec, 0x19, 0,
14714 AC_VERB_SET_PIN_WIDGET_CONTROL,
14715 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014716 }
14717 return alc_check_power_status(codec, nid);
14718}
14719#endif /* CONFIG_SND_HDA_POWER_SAVE */
14720
Takashi Iwai840b64c2010-07-13 22:49:01 +020014721static int alc275_setup_dual_adc(struct hda_codec *codec)
14722{
14723 struct alc_spec *spec = codec->spec;
14724
14725 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14726 return 0;
14727 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14728 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14729 if (spec->ext_mic.pin <= 0x12) {
14730 spec->private_adc_nids[0] = 0x08;
14731 spec->private_adc_nids[1] = 0x11;
14732 spec->private_capsrc_nids[0] = 0x23;
14733 spec->private_capsrc_nids[1] = 0x22;
14734 } else {
14735 spec->private_adc_nids[0] = 0x11;
14736 spec->private_adc_nids[1] = 0x08;
14737 spec->private_capsrc_nids[0] = 0x22;
14738 spec->private_capsrc_nids[1] = 0x23;
14739 }
14740 spec->adc_nids = spec->private_adc_nids;
14741 spec->capsrc_nids = spec->private_capsrc_nids;
14742 spec->num_adc_nids = 2;
14743 spec->dual_adc_switch = 1;
14744 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14745 spec->adc_nids[0], spec->adc_nids[1]);
14746 return 1;
14747 }
14748 return 0;
14749}
14750
Takashi Iwaid433a672010-09-20 15:11:54 +020014751/* different alc269-variants */
14752enum {
14753 ALC269_TYPE_NORMAL,
Kailang Yang48c88e82010-11-23 08:56:16 +010014754 ALC269_TYPE_ALC258,
Takashi Iwaid433a672010-09-20 15:11:54 +020014755 ALC269_TYPE_ALC259,
Kailang Yang48c88e82010-11-23 08:56:16 +010014756 ALC269_TYPE_ALC269VB,
14757 ALC269_TYPE_ALC270,
Takashi Iwaid433a672010-09-20 15:11:54 +020014758 ALC269_TYPE_ALC271X,
14759};
14760
Kailang Yangf6a92242007-12-13 16:52:54 +010014761/*
14762 * BIOS auto configuration
14763 */
14764static int alc269_parse_auto_config(struct hda_codec *codec)
14765{
14766 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014767 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014768 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Kailang Yangf6a92242007-12-13 16:52:54 +010014769
14770 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14771 alc269_ignore);
14772 if (err < 0)
14773 return err;
14774
14775 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14776 if (err < 0)
14777 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014778 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14779 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14780 else
14781 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14782 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014783 if (err < 0)
14784 return err;
14785
14786 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14787
Takashi Iwai757899a2010-07-30 10:48:14 +020014788 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014789
Takashi Iwai603c4012008-07-30 15:01:44 +020014790 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014791 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014792
Takashi Iwaid433a672010-09-20 15:11:54 +020014793 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014794 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014795 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014796 } else {
14797 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014798 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014799 }
14800
Kailang Yangf6a92242007-12-13 16:52:54 +010014801 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014802 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014803
14804 if (!alc275_setup_dual_adc(codec))
14805 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14806 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014807
Kailang Yangf6a92242007-12-13 16:52:54 +010014808 err = alc_auto_add_mic_boost(codec);
14809 if (err < 0)
14810 return err;
14811
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014812 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014813 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014814
Kailang Yangf6a92242007-12-13 16:52:54 +010014815 return 1;
14816}
14817
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014818#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14819#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014820#define alc269_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010014821#define alc269_auto_init_input_src alc882_auto_init_input_src
Kailang Yangf6a92242007-12-13 16:52:54 +010014822
14823
14824/* init callback for auto-configuration model -- overriding the default init */
14825static void alc269_auto_init(struct hda_codec *codec)
14826{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014827 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014828 alc269_auto_init_multi_out(codec);
14829 alc269_auto_init_hp_out(codec);
14830 alc269_auto_init_analog_input(codec);
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010014831 if (!spec->dual_adc_switch)
14832 alc269_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014833 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014834 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014835 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014836}
14837
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014838static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14839{
14840 int val = alc_read_coef_idx(codec, 0x04);
14841 if (power_up)
14842 val |= 1 << 11;
14843 else
14844 val &= ~(1 << 11);
14845 alc_write_coef_idx(codec, 0x04, val);
14846}
14847
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014848static void alc269_shutup(struct hda_codec *codec)
Kailang Yang977ddd62010-09-15 10:02:29 +020014849{
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014850 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14851 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014852 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014853 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014854 msleep(150);
14855 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014856}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014857
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014858#ifdef SND_HDA_NEEDS_RESUME
Kailang Yang977ddd62010-09-15 10:02:29 +020014859static int alc269_resume(struct hda_codec *codec)
14860{
Kailang Yang977ddd62010-09-15 10:02:29 +020014861 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014862 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014863 msleep(150);
14864 }
14865
14866 codec->patch_ops.init(codec);
14867
14868 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014869 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014870 msleep(200);
14871 }
14872
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014873 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14874 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014875
14876 snd_hda_codec_resume_amp(codec);
14877 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014878 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014879 return 0;
14880}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014881#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014882
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014883static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014884 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014885{
14886 int coef;
14887
Takashi Iwai58701122011-01-13 15:41:45 +010014888 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef22011-01-13 14:40:43 +010014889 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014890 coef = alc_read_coef_idx(codec, 0x1e);
14891 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14892}
14893
Takashi Iwai6981d182011-04-15 10:11:12 +020014894static void alc271_fixup_dmic(struct hda_codec *codec,
14895 const struct alc_fixup *fix, int action)
14896{
Takashi Iwaia9111322011-05-02 11:30:18 +020014897 static const struct hda_verb verbs[] = {
Takashi Iwai6981d182011-04-15 10:11:12 +020014898 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14899 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14900 {}
14901 };
14902 unsigned int cfg;
14903
14904 if (strcmp(codec->chip_name, "ALC271X"))
14905 return;
14906 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
14907 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
14908 snd_hda_sequence_write(codec, verbs);
14909}
14910
Takashi Iwaiff818c22010-04-12 08:59:25 +020014911enum {
14912 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014913 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014914 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014915 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014916 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014917 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014918 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwai6981d182011-04-15 10:11:12 +020014919 ALC271_FIXUP_DMIC,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014920};
14921
Takashi Iwaiff818c22010-04-12 08:59:25 +020014922static const struct alc_fixup alc269_fixups[] = {
14923 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014924 .type = ALC_FIXUP_VERBS,
14925 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014926 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14927 {}
14928 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014929 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014930 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014931 .type = ALC_FIXUP_VERBS,
14932 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014933 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14934 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14935 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14936 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014937 },
14938 .chained = true,
14939 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014940 },
David Henningsson145a9022010-09-16 10:07:53 +020014941 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014942 .type = ALC_FIXUP_VERBS,
14943 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014944 /* Enables internal speaker */
14945 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14946 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14947 {}
14948 }
14949 },
David Henningsson022c92b2010-12-17 20:43:04 +010014950 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014951 .type = ALC_FIXUP_SKU,
14952 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014953 },
David Henningssonac612402010-12-15 09:18:18 +010014954 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014955 .type = ALC_FIXUP_PINS,
14956 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014957 { 0x17, 0x99130111 }, /* subwoofer */
14958 { }
14959 }
14960 },
Kailang Yang357f9152011-01-12 08:12:52 +010014961 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014962 .type = ALC_FIXUP_VERBS,
14963 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014964 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14965 {}
14966 }
14967 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014968 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014969 .type = ALC_FIXUP_FUNC,
14970 .v.func = alc269_fixup_hweq,
14971 .chained = true,
14972 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Takashi Iwai6981d182011-04-15 10:11:12 +020014973 },
14974 [ALC271_FIXUP_DMIC] = {
14975 .type = ALC_FIXUP_FUNC,
14976 .v.func = alc271_fixup_dmic,
14977 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014978};
14979
Takashi Iwaia9111322011-05-02 11:30:18 +020014980static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014981 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014982 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14983 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014984 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014985 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwai6981d182011-04-15 10:11:12 +020014986 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
David Henningsson022c92b2010-12-17 20:43:04 +010014987 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonded9f522011-01-26 11:46:12 +010014988 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
14989 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14990 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
14991 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014992 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014993 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014994 {}
14995};
14996
14997
Kailang Yangf6a92242007-12-13 16:52:54 +010014998/*
14999 * configuration and preset
15000 */
Takashi Iwaiea734962011-01-17 11:29:34 +010015001static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020015002 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020015003 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010015004 [ALC269_AMIC] = "laptop-amic",
15005 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000015006 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020015007 [ALC269_LIFEBOOK] = "lifebook",
15008 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010015009};
15010
Takashi Iwaia9111322011-05-02 11:30:18 +020015011static const struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020015012 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015013 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020015014 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010015015 ALC269_AMIC),
15016 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
15017 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
15018 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
15019 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
15020 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
15021 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
15022 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
15023 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
15024 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
Chih-Wei Huangc790ad32011-02-25 11:14:31 +080015025 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
Kailang Yang84898e82010-02-04 14:16:14 +010015026 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
15027 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
15028 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
15029 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
15030 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
15031 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
15032 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
15033 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
15034 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
15035 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
15036 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
15037 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
15038 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
15039 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
15040 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
15041 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
15042 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
15043 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
15044 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
15045 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
15046 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
15047 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
15048 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
15049 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
15050 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
15051 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020015052 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010015053 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020015054 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010015055 ALC269_DMIC),
15056 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
15057 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020015058 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000015059 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010015060 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
15061 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
15062 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
15063 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
15064 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
15065 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010015066 {}
15067};
15068
Takashi Iwaia9111322011-05-02 11:30:18 +020015069static const struct alc_config_preset alc269_presets[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010015070 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015071 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010015072 .init_verbs = { alc269_init_verbs },
15073 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15074 .dac_nids = alc269_dac_nids,
15075 .hp_nid = 0x03,
15076 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15077 .channel_mode = alc269_modes,
15078 .input_mux = &alc269_capture_source,
15079 },
Kailang Yang60db6b52008-08-26 13:13:00 +020015080 [ALC269_QUANTA_FL1] = {
15081 .mixers = { alc269_quanta_fl1_mixer },
15082 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
15083 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15084 .dac_nids = alc269_dac_nids,
15085 .hp_nid = 0x03,
15086 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15087 .channel_mode = alc269_modes,
15088 .input_mux = &alc269_capture_source,
15089 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015090 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020015091 .init_hook = alc269_quanta_fl1_init_hook,
15092 },
Kailang Yang84898e82010-02-04 14:16:14 +010015093 [ALC269_AMIC] = {
15094 .mixers = { alc269_laptop_mixer },
15095 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015096 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015097 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015098 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15099 .dac_nids = alc269_dac_nids,
15100 .hp_nid = 0x03,
15101 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15102 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015103 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015104 .setup = alc269_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015105 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015106 },
Kailang Yang84898e82010-02-04 14:16:14 +010015107 [ALC269_DMIC] = {
15108 .mixers = { alc269_laptop_mixer },
15109 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015110 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015111 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015112 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15113 .dac_nids = alc269_dac_nids,
15114 .hp_nid = 0x03,
15115 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15116 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015117 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015118 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015119 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010015120 },
15121 [ALC269VB_AMIC] = {
15122 .mixers = { alc269vb_laptop_mixer },
15123 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
15124 .init_verbs = { alc269vb_init_verbs,
15125 alc269vb_laptop_amic_init_verbs },
15126 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15127 .dac_nids = alc269_dac_nids,
15128 .hp_nid = 0x03,
15129 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15130 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015131 .unsol_event = alc_sku_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020015132 .setup = alc269vb_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015133 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010015134 },
15135 [ALC269VB_DMIC] = {
15136 .mixers = { alc269vb_laptop_mixer },
15137 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15138 .init_verbs = { alc269vb_init_verbs,
15139 alc269vb_laptop_dmic_init_verbs },
15140 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15141 .dac_nids = alc269_dac_nids,
15142 .hp_nid = 0x03,
15143 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15144 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015145 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015146 .setup = alc269vb_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015147 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015148 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015149 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015150 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010015151 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015152 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015153 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015154 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15155 .dac_nids = alc269_dac_nids,
15156 .hp_nid = 0x03,
15157 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15158 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015159 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015160 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015161 .init_hook = alc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015162 },
Tony Vroon64154832008-11-06 15:08:49 +000015163 [ALC269_LIFEBOOK] = {
15164 .mixers = { alc269_lifebook_mixer },
15165 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
15166 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15167 .dac_nids = alc269_dac_nids,
15168 .hp_nid = 0x03,
15169 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15170 .channel_mode = alc269_modes,
15171 .input_mux = &alc269_capture_source,
15172 .unsol_event = alc269_lifebook_unsol_event,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015173 .setup = alc269_lifebook_setup,
Tony Vroon64154832008-11-06 15:08:49 +000015174 .init_hook = alc269_lifebook_init_hook,
15175 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015176 [ALC271_ACER] = {
15177 .mixers = { alc269_asus_mixer },
15178 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15179 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
15180 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15181 .dac_nids = alc269_dac_nids,
15182 .adc_nids = alc262_dmic_adc_nids,
15183 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
15184 .capsrc_nids = alc262_dmic_capsrc_nids,
15185 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15186 .channel_mode = alc269_modes,
15187 .input_mux = &alc269_capture_source,
15188 .dig_out_nid = ALC880_DIGOUT_NID,
15189 .unsol_event = alc_sku_unsol_event,
15190 .setup = alc269vb_laptop_dmic_setup,
15191 .init_hook = alc_inithook,
15192 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015193};
15194
Kailang Yang977ddd62010-09-15 10:02:29 +020015195static int alc269_fill_coef(struct hda_codec *codec)
15196{
15197 int val;
15198
15199 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
15200 alc_write_coef_idx(codec, 0xf, 0x960b);
15201 alc_write_coef_idx(codec, 0xe, 0x8817);
15202 }
15203
15204 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
15205 alc_write_coef_idx(codec, 0xf, 0x960b);
15206 alc_write_coef_idx(codec, 0xe, 0x8814);
15207 }
15208
15209 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
15210 val = alc_read_coef_idx(codec, 0x04);
15211 /* Power up output pin */
15212 alc_write_coef_idx(codec, 0x04, val | (1<<11));
15213 }
15214
15215 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
15216 val = alc_read_coef_idx(codec, 0xd);
15217 if ((val & 0x0c00) >> 10 != 0x1) {
15218 /* Capless ramp up clock control */
Kailang Yangb896b4e2011-05-18 11:53:16 +020015219 alc_write_coef_idx(codec, 0xd, val | (1<<10));
Kailang Yang977ddd62010-09-15 10:02:29 +020015220 }
15221 val = alc_read_coef_idx(codec, 0x17);
15222 if ((val & 0x01c0) >> 6 != 0x4) {
15223 /* Class D power on reset */
Kailang Yangb896b4e2011-05-18 11:53:16 +020015224 alc_write_coef_idx(codec, 0x17, val | (1<<7));
Kailang Yang977ddd62010-09-15 10:02:29 +020015225 }
15226 }
Kailang Yangb896b4e2011-05-18 11:53:16 +020015227
15228 val = alc_read_coef_idx(codec, 0xd); /* Class D */
15229 alc_write_coef_idx(codec, 0xd, val | (1<<14));
15230
15231 val = alc_read_coef_idx(codec, 0x4); /* HP */
15232 alc_write_coef_idx(codec, 0x4, val | (1<<11));
15233
Kailang Yang977ddd62010-09-15 10:02:29 +020015234 return 0;
15235}
15236
Kailang Yangf6a92242007-12-13 16:52:54 +010015237static int patch_alc269(struct hda_codec *codec)
15238{
15239 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010015240 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010015241 int err;
15242
15243 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15244 if (spec == NULL)
15245 return -ENOMEM;
15246
15247 codec->spec = spec;
15248
Kailang Yangda00c242010-03-19 11:23:45 +010015249 alc_auto_parse_customize_define(codec);
15250
Kailang Yangc793bec2010-12-21 09:14:13 +010015251 if (codec->vendor_id == 0x10ec0269) {
15252 coef = alc_read_coef_idx(codec, 0);
15253 if ((coef & 0x00f0) == 0x0010) {
15254 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
15255 spec->cdefine.platform_type == 1) {
15256 alc_codec_rename(codec, "ALC271X");
15257 spec->codec_variant = ALC269_TYPE_ALC271X;
15258 } else if ((coef & 0xf000) == 0x1000) {
15259 spec->codec_variant = ALC269_TYPE_ALC270;
15260 } else if ((coef & 0xf000) == 0x2000) {
15261 alc_codec_rename(codec, "ALC259");
15262 spec->codec_variant = ALC269_TYPE_ALC259;
15263 } else if ((coef & 0xf000) == 0x3000) {
15264 alc_codec_rename(codec, "ALC258");
15265 spec->codec_variant = ALC269_TYPE_ALC258;
15266 } else {
15267 alc_codec_rename(codec, "ALC269VB");
15268 spec->codec_variant = ALC269_TYPE_ALC269VB;
15269 }
15270 } else
15271 alc_fix_pll_init(codec, 0x20, 0x04, 15);
15272 alc269_fill_coef(codec);
15273 }
Kailang Yang977ddd62010-09-15 10:02:29 +020015274
Kailang Yangf6a92242007-12-13 16:52:54 +010015275 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15276 alc269_models,
15277 alc269_cfg_tbl);
15278
15279 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015280 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15281 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015282 board_config = ALC269_AUTO;
15283 }
15284
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015285 if (board_config == ALC269_AUTO) {
15286 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
15287 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
15288 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020015289
Kailang Yangf6a92242007-12-13 16:52:54 +010015290 if (board_config == ALC269_AUTO) {
15291 /* automatic parse from the BIOS config */
15292 err = alc269_parse_auto_config(codec);
15293 if (err < 0) {
15294 alc_free(codec);
15295 return err;
15296 } else if (!err) {
15297 printk(KERN_INFO
15298 "hda_codec: Cannot set up configuration "
15299 "from BIOS. Using base mode...\n");
15300 board_config = ALC269_BASIC;
15301 }
15302 }
15303
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015304 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015305 err = snd_hda_attach_beep_device(codec, 0x1);
15306 if (err < 0) {
15307 alc_free(codec);
15308 return err;
15309 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015310 }
15311
Kailang Yangf6a92242007-12-13 16:52:54 +010015312 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015313 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015314
Kailang Yang84898e82010-02-04 14:16:14 +010015315 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015316 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15317 * fix the sample rate of analog I/O to 44.1kHz
15318 */
15319 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15320 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015321 } else if (spec->dual_adc_switch) {
15322 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15323 /* switch ADC dynamically */
15324 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015325 } else {
15326 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15327 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15328 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015329 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15330 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15331
Takashi Iwai66946352010-03-29 17:21:45 +020015332 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Kailang Yang1657cbd2010-11-23 08:53:32 +010015333 if (spec->codec_variant == ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015334 spec->adc_nids = alc269_adc_nids;
15335 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15336 spec->capsrc_nids = alc269_capsrc_nids;
15337 } else {
15338 spec->adc_nids = alc269vb_adc_nids;
15339 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15340 spec->capsrc_nids = alc269vb_capsrc_nids;
15341 }
Kailang Yang84898e82010-02-04 14:16:14 +010015342 }
15343
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015344 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015345 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015346 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015347 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015348
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015349 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020015350
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015351 spec->vmaster_nid = 0x02;
15352
Kailang Yangf6a92242007-12-13 16:52:54 +010015353 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015354#ifdef SND_HDA_NEEDS_RESUME
15355 codec->patch_ops.resume = alc269_resume;
15356#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015357 if (board_config == ALC269_AUTO)
15358 spec->init_hook = alc269_auto_init;
Takashi Iwai5402e4c2011-04-07 10:39:25 +020015359 spec->shutup = alc269_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020015360
15361 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010015362#ifdef CONFIG_SND_HDA_POWER_SAVE
15363 if (!spec->loopback.amplist)
15364 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015365 if (alc269_mic2_for_mute_led(codec))
15366 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015367#endif
15368
15369 return 0;
15370}
15371
15372/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015373 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15374 */
15375
15376/*
15377 * set the path ways for 2 channel output
15378 * need to set the codec line out and mic 1 pin widgets to inputs
15379 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015380static const struct hda_verb alc861_threestack_ch2_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015381 /* set pin widget 1Ah (line in) for input */
15382 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015383 /* set pin widget 18h (mic1/2) for input, for mic also enable
15384 * the vref
15385 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015386 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15387
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015388 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15389#if 0
15390 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15391 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15392#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015393 { } /* end */
15394};
15395/*
15396 * 6ch mode
15397 * need to set the codec line out and mic 1 pin widgets to outputs
15398 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015399static const struct hda_verb alc861_threestack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015400 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15401 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15402 /* set pin widget 18h (mic1) for output (CLFE)*/
15403 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15404
15405 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015406 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015407
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015408 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15409#if 0
15410 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15411 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15412#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015413 { } /* end */
15414};
15415
Takashi Iwaia9111322011-05-02 11:30:18 +020015416static const struct hda_channel_mode alc861_threestack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015417 { 2, alc861_threestack_ch2_init },
15418 { 6, alc861_threestack_ch6_init },
15419};
Takashi Iwai22309c32006-08-09 16:57:28 +020015420/* Set mic1 as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015421static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015422 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15423 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15424 { } /* end */
15425};
15426/* Set mic1 as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015427static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015428 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15429 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15430 { } /* end */
15431};
15432
Takashi Iwaia9111322011-05-02 11:30:18 +020015433static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015434 { 2, alc861_uniwill_m31_ch2_init },
15435 { 4, alc861_uniwill_m31_ch4_init },
15436};
Kailang Yangdf694da2005-12-05 19:42:22 +010015437
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015438/* Set mic1 and line-in as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015439static const struct hda_verb alc861_asus_ch2_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015440 /* set pin widget 1Ah (line in) for input */
15441 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015442 /* set pin widget 18h (mic1/2) for input, for mic also enable
15443 * the vref
15444 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015445 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15446
15447 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15448#if 0
15449 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15450 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15451#endif
15452 { } /* end */
15453};
15454/* Set mic1 nad line-in as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015455static const struct hda_verb alc861_asus_ch6_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015456 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15457 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15458 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15459 /* set pin widget 18h (mic1) for output (CLFE)*/
15460 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15461 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15462 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15463 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15464
15465 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15466#if 0
15467 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15468 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15469#endif
15470 { } /* end */
15471};
15472
Takashi Iwaia9111322011-05-02 11:30:18 +020015473static const struct hda_channel_mode alc861_asus_modes[2] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015474 { 2, alc861_asus_ch2_init },
15475 { 6, alc861_asus_ch6_init },
15476};
15477
Kailang Yangdf694da2005-12-05 19:42:22 +010015478/* patch-ALC861 */
15479
Takashi Iwaia9111322011-05-02 11:30:18 +020015480static const struct snd_kcontrol_new alc861_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015481 /* output mixer control */
15482 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15483 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15484 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15485 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15486 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15487
15488 /*Input mixer control */
15489 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15490 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15491 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15492 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15493 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15494 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15495 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15496 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15497 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15498 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015499
Kailang Yangdf694da2005-12-05 19:42:22 +010015500 { } /* end */
15501};
15502
Takashi Iwaia9111322011-05-02 11:30:18 +020015503static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015504 /* output mixer control */
15505 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15506 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15507 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15508 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15509 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15510
15511 /* Input mixer control */
15512 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15513 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15514 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15515 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15516 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15517 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15518 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15519 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15520 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15521 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015522
Kailang Yangdf694da2005-12-05 19:42:22 +010015523 {
15524 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15525 .name = "Channel Mode",
15526 .info = alc_ch_mode_info,
15527 .get = alc_ch_mode_get,
15528 .put = alc_ch_mode_put,
15529 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15530 },
15531 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015532};
15533
Takashi Iwaia9111322011-05-02 11:30:18 +020015534static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015535 /* output mixer control */
15536 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15537 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15538 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015539
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015540 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015541};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015542
Takashi Iwaia9111322011-05-02 11:30:18 +020015543static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015544 /* output mixer control */
15545 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15546 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15547 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15548 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15549 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15550
15551 /* Input mixer control */
15552 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15553 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15554 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15555 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15556 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15557 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15558 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15559 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15560 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15561 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015562
Takashi Iwai22309c32006-08-09 16:57:28 +020015563 {
15564 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15565 .name = "Channel Mode",
15566 .info = alc_ch_mode_info,
15567 .get = alc_ch_mode_get,
15568 .put = alc_ch_mode_put,
15569 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15570 },
15571 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015572};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015573
Takashi Iwaia9111322011-05-02 11:30:18 +020015574static const struct snd_kcontrol_new alc861_asus_mixer[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015575 /* output mixer control */
15576 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15577 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15578 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15579 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15580 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15581
15582 /* Input mixer control */
15583 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15584 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15585 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15586 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15587 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15588 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15589 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15590 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15591 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015592 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15593
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015594 {
15595 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15596 .name = "Channel Mode",
15597 .info = alc_ch_mode_info,
15598 .get = alc_ch_mode_get,
15599 .put = alc_ch_mode_put,
15600 .private_value = ARRAY_SIZE(alc861_asus_modes),
15601 },
15602 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015603};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015604
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015605/* additional mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015606static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015607 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15608 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015609 { }
15610};
15611
Kailang Yangdf694da2005-12-05 19:42:22 +010015612/*
15613 * generic initialization of ADC, input mixers and output mixers
15614 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015615static const struct hda_verb alc861_base_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015616 /*
15617 * Unmute ADC0 and set the default input to mic-in
15618 */
15619 /* port-A for surround (rear panel) */
15620 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15621 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15622 /* port-B for mic-in (rear panel) with vref */
15623 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15624 /* port-C for line-in (rear panel) */
15625 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15626 /* port-D for Front */
15627 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15628 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15629 /* port-E for HP out (front panel) */
15630 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15631 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015632 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015633 /* port-F for mic-in (front panel) with vref */
15634 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15635 /* port-G for CLFE (rear panel) */
15636 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15637 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15638 /* port-H for side (rear panel) */
15639 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15640 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15641 /* CD-in */
15642 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15643 /* route front mic to ADC1*/
15644 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15645 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015646
Kailang Yangdf694da2005-12-05 19:42:22 +010015647 /* Unmute DAC0~3 & spdif out*/
15648 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15649 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15650 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15651 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15652 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015653
Kailang Yangdf694da2005-12-05 19:42:22 +010015654 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15655 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15656 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15657 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15658 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015659
Kailang Yangdf694da2005-12-05 19:42:22 +010015660 /* Unmute Stereo Mixer 15 */
15661 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15662 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15663 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015664 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015665
15666 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15667 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15668 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15669 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15670 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15671 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15672 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15673 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015674 /* hp used DAC 3 (Front) */
15675 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015676 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15677
15678 { }
15679};
15680
Takashi Iwaia9111322011-05-02 11:30:18 +020015681static const struct hda_verb alc861_threestack_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015682 /*
15683 * Unmute ADC0 and set the default input to mic-in
15684 */
15685 /* port-A for surround (rear panel) */
15686 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15687 /* port-B for mic-in (rear panel) with vref */
15688 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15689 /* port-C for line-in (rear panel) */
15690 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15691 /* port-D for Front */
15692 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15693 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15694 /* port-E for HP out (front panel) */
15695 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15696 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015697 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015698 /* port-F for mic-in (front panel) with vref */
15699 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15700 /* port-G for CLFE (rear panel) */
15701 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15702 /* port-H for side (rear panel) */
15703 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15704 /* CD-in */
15705 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15706 /* route front mic to ADC1*/
15707 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15708 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15709 /* Unmute DAC0~3 & spdif out*/
15710 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15711 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15712 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15713 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15714 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015715
Kailang Yangdf694da2005-12-05 19:42:22 +010015716 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15717 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15718 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15719 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15720 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015721
Kailang Yangdf694da2005-12-05 19:42:22 +010015722 /* Unmute Stereo Mixer 15 */
15723 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15724 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15725 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015726 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015727
15728 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15729 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15730 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15731 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15732 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15733 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15734 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15735 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015736 /* hp used DAC 3 (Front) */
15737 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015738 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15739 { }
15740};
Takashi Iwai22309c32006-08-09 16:57:28 +020015741
Takashi Iwaia9111322011-05-02 11:30:18 +020015742static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015743 /*
15744 * Unmute ADC0 and set the default input to mic-in
15745 */
15746 /* port-A for surround (rear panel) */
15747 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15748 /* port-B for mic-in (rear panel) with vref */
15749 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15750 /* port-C for line-in (rear panel) */
15751 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15752 /* port-D for Front */
15753 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15754 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15755 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015756 /* this has to be set to VREF80 */
15757 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015758 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015759 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015760 /* port-F for mic-in (front panel) with vref */
15761 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15762 /* port-G for CLFE (rear panel) */
15763 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15764 /* port-H for side (rear panel) */
15765 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15766 /* CD-in */
15767 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15768 /* route front mic to ADC1*/
15769 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15770 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15771 /* Unmute DAC0~3 & spdif out*/
15772 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15773 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15774 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15775 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15776 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015777
Takashi Iwai22309c32006-08-09 16:57:28 +020015778 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15779 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15780 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15781 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15782 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015783
Takashi Iwai22309c32006-08-09 16:57:28 +020015784 /* Unmute Stereo Mixer 15 */
15785 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15786 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15787 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015788 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015789
15790 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15791 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15792 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15793 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15794 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15795 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15796 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15797 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015798 /* hp used DAC 3 (Front) */
15799 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015800 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15801 { }
15802};
15803
Takashi Iwaia9111322011-05-02 11:30:18 +020015804static const struct hda_verb alc861_asus_init_verbs[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015805 /*
15806 * Unmute ADC0 and set the default input to mic-in
15807 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015808 /* port-A for surround (rear panel)
15809 * according to codec#0 this is the HP jack
15810 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015811 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15812 /* route front PCM to HP */
15813 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15814 /* port-B for mic-in (rear panel) with vref */
15815 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15816 /* port-C for line-in (rear panel) */
15817 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15818 /* port-D for Front */
15819 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15820 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15821 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015822 /* this has to be set to VREF80 */
15823 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015824 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015825 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015826 /* port-F for mic-in (front panel) with vref */
15827 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15828 /* port-G for CLFE (rear panel) */
15829 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15830 /* port-H for side (rear panel) */
15831 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15832 /* CD-in */
15833 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15834 /* route front mic to ADC1*/
15835 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15836 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15837 /* Unmute DAC0~3 & spdif out*/
15838 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15839 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15840 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15841 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15842 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15843 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15844 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15845 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15846 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15847 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015848
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015849 /* Unmute Stereo Mixer 15 */
15850 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15851 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15852 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015853 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015854
15855 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15856 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15857 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15858 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15859 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15860 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15861 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15862 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015863 /* hp used DAC 3 (Front) */
15864 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015865 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15866 { }
15867};
15868
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015869/* additional init verbs for ASUS laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020015870static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015871 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15872 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15873 { }
15874};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015875
Kailang Yangdf694da2005-12-05 19:42:22 +010015876/*
15877 * generic initialization of ADC, input mixers and output mixers
15878 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015879static const struct hda_verb alc861_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015880 /*
15881 * Unmute ADC0 and set the default input to mic-in
15882 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015883 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015884 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015885
Kailang Yangdf694da2005-12-05 19:42:22 +010015886 /* Unmute DAC0~3 & spdif out*/
15887 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15888 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15889 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15890 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15891 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015892
Kailang Yangdf694da2005-12-05 19:42:22 +010015893 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15894 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15895 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15896 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15897 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015898
Kailang Yangdf694da2005-12-05 19:42:22 +010015899 /* Unmute Stereo Mixer 15 */
15900 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15901 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15902 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15903 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15904
Takashi Iwai1c209302009-07-22 15:17:45 +020015905 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15906 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15907 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15908 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15909 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15910 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15911 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15912 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015913
15914 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15915 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015916 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15917 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015918 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15919 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015920 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15921 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015922
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015923 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015924
15925 { }
15926};
15927
Takashi Iwaia9111322011-05-02 11:30:18 +020015928static const struct hda_verb alc861_toshiba_init_verbs[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015929 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015930
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015931 { }
15932};
15933
15934/* toggle speaker-output according to the hp-jack state */
15935static void alc861_toshiba_automute(struct hda_codec *codec)
15936{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015937 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015938
Takashi Iwai47fd8302007-08-10 17:11:07 +020015939 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15940 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15941 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15942 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015943}
15944
15945static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15946 unsigned int res)
15947{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015948 if ((res >> 26) == ALC880_HP_EVENT)
15949 alc861_toshiba_automute(codec);
15950}
15951
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015952/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015953#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15954#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15955#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15956#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15957
15958
15959#define ALC861_DIGOUT_NID 0x07
15960
Takashi Iwaia9111322011-05-02 11:30:18 +020015961static const struct hda_channel_mode alc861_8ch_modes[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015962 { 8, NULL }
15963};
15964
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015965static const hda_nid_t alc861_dac_nids[4] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015966 /* front, surround, clfe, side */
15967 0x03, 0x06, 0x05, 0x04
15968};
15969
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015970static const hda_nid_t alc660_dac_nids[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015971 /* front, clfe, surround */
15972 0x03, 0x05, 0x06
15973};
15974
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015975static const hda_nid_t alc861_adc_nids[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015976 /* ADC0-2 */
15977 0x08,
15978};
15979
Takashi Iwaia9111322011-05-02 11:30:18 +020015980static const struct hda_input_mux alc861_capture_source = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015981 .num_items = 5,
15982 .items = {
15983 { "Mic", 0x0 },
15984 { "Front Mic", 0x3 },
15985 { "Line", 0x1 },
15986 { "CD", 0x4 },
15987 { "Mixer", 0x5 },
15988 },
15989};
15990
Takashi Iwai1c209302009-07-22 15:17:45 +020015991static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15992{
15993 struct alc_spec *spec = codec->spec;
15994 hda_nid_t mix, srcs[5];
15995 int i, j, num;
15996
15997 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15998 return 0;
15999 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
16000 if (num < 0)
16001 return 0;
16002 for (i = 0; i < num; i++) {
16003 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020016004 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020016005 if (type != AC_WID_AUD_OUT)
16006 continue;
16007 for (j = 0; j < spec->multiout.num_dacs; j++)
16008 if (spec->multiout.dac_nids[j] == srcs[i])
16009 break;
16010 if (j >= spec->multiout.num_dacs)
16011 return srcs[i];
16012 }
16013 return 0;
16014}
16015
Kailang Yangdf694da2005-12-05 19:42:22 +010016016/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020016017static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016018 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016019{
Takashi Iwai1c209302009-07-22 15:17:45 +020016020 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016021 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020016022 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010016023
16024 spec->multiout.dac_nids = spec->private_dac_nids;
16025 for (i = 0; i < cfg->line_outs; i++) {
16026 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020016027 dac = alc861_look_for_dac(codec, nid);
16028 if (!dac)
16029 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020016030 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010016031 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016032 return 0;
16033}
16034
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016035static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
16036 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016037{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016038 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020016039 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
16040}
16041
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016042#define alc861_create_out_sw(codec, pfx, nid, chs) \
16043 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
16044
Takashi Iwai1c209302009-07-22 15:17:45 +020016045/* add playback controls from the parsed DAC table */
16046static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
16047 const struct auto_pin_cfg *cfg)
16048{
16049 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010016050 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016051 "Front", "Surround", NULL /*CLFE*/, "Side"
16052 };
Takashi Iwaice764ab2011-04-27 16:35:23 +020016053 const char *pfx = alc_get_line_out_pfx(spec, true);
Kailang Yangdf694da2005-12-05 19:42:22 +010016054 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016055 int i, err, noutputs;
Takashi Iwai1c209302009-07-22 15:17:45 +020016056
Takashi Iwaice764ab2011-04-27 16:35:23 +020016057 noutputs = cfg->line_outs;
16058 if (spec->multi_ios > 0)
16059 noutputs += spec->multi_ios;
16060
16061 for (i = 0; i < noutputs; i++) {
Kailang Yangdf694da2005-12-05 19:42:22 +010016062 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016063 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010016064 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016065 if (!pfx && i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010016066 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020016067 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016068 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016069 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016070 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016071 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016072 return err;
16073 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016074 const char *name = pfx;
David Henningsson5a882642011-03-23 08:35:07 +010016075 int index = i;
16076 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016077 name = chname[i];
David Henningsson5a882642011-03-23 08:35:07 +010016078 index = 0;
16079 }
16080 err = __alc861_create_out_sw(codec, name, nid, index, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016081 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016082 return err;
16083 }
16084 }
16085 return 0;
16086}
16087
Takashi Iwai1c209302009-07-22 15:17:45 +020016088static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016089{
Takashi Iwai1c209302009-07-22 15:17:45 +020016090 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016091 int err;
16092 hda_nid_t nid;
16093
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016094 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016095 return 0;
16096
16097 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020016098 nid = alc861_look_for_dac(codec, pin);
16099 if (nid) {
16100 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
16101 if (err < 0)
16102 return err;
16103 spec->multiout.hp_nid = nid;
16104 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016105 }
16106 return 0;
16107}
16108
16109/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016110static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016111 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016112{
Takashi Iwai05f5f472009-08-25 13:10:18 +020016113 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010016114}
16115
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016116static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
16117 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020016118 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010016119{
Takashi Iwai1c209302009-07-22 15:17:45 +020016120 hda_nid_t mix, srcs[5];
16121 int i, num;
16122
Jacek Luczak564c5be2008-05-03 18:41:23 +020016123 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
16124 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020016125 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020016126 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020016127 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
16128 return;
16129 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
16130 if (num < 0)
16131 return;
16132 for (i = 0; i < num; i++) {
16133 unsigned int mute;
16134 if (srcs[i] == dac || srcs[i] == 0x15)
16135 mute = AMP_IN_UNMUTE(i);
16136 else
16137 mute = AMP_IN_MUTE(i);
16138 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16139 mute);
16140 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016141}
16142
16143static void alc861_auto_init_multi_out(struct hda_codec *codec)
16144{
16145 struct alc_spec *spec = codec->spec;
16146 int i;
16147
16148 for (i = 0; i < spec->autocfg.line_outs; i++) {
16149 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016150 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016151 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016152 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016153 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016154 }
16155}
16156
16157static void alc861_auto_init_hp_out(struct hda_codec *codec)
16158{
16159 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016160
Takashi Iwai15870f02009-10-05 08:25:13 +020016161 if (spec->autocfg.hp_outs)
16162 alc861_auto_set_output_and_unmute(codec,
16163 spec->autocfg.hp_pins[0],
16164 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020016165 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020016166 if (spec->autocfg.speaker_outs)
16167 alc861_auto_set_output_and_unmute(codec,
16168 spec->autocfg.speaker_pins[0],
16169 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020016170 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016171}
16172
16173static void alc861_auto_init_analog_input(struct hda_codec *codec)
16174{
16175 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016176 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010016177 int i;
16178
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016179 for (i = 0; i < cfg->num_inputs; i++) {
16180 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010016181 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020016182 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016183 }
16184}
16185
16186/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016187/* return 1 if successful, 0 if the proper config is not found,
16188 * or a negative error code
16189 */
Kailang Yangdf694da2005-12-05 19:42:22 +010016190static int alc861_parse_auto_config(struct hda_codec *codec)
16191{
16192 struct alc_spec *spec = codec->spec;
16193 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016194 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010016195
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016196 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16197 alc861_ignore);
16198 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016199 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016200 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016201 return 0; /* can't find valid BIOS pin config */
16202
Takashi Iwai1c209302009-07-22 15:17:45 +020016203 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016204 if (err < 0)
16205 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016206 err = alc_auto_add_multi_channel_mode(codec);
16207 if (err < 0)
16208 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016209 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016210 if (err < 0)
16211 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016212 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016213 if (err < 0)
16214 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016215 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016216 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016217 return err;
16218
16219 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16220
Takashi Iwai757899a2010-07-30 10:48:14 +020016221 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016222
Takashi Iwai603c4012008-07-30 15:01:44 +020016223 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016224 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010016225
Takashi Iwaid88897e2008-10-31 15:01:37 +010016226 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010016227
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020016228 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016229 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010016230
16231 spec->adc_nids = alc861_adc_nids;
16232 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016233 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016234
Kailang Yang6227cdc2010-02-25 08:36:52 +010016235 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016236
Kailang Yangdf694da2005-12-05 19:42:22 +010016237 return 1;
16238}
16239
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016240/* additional initialization for auto-configuration model */
16241static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010016242{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016243 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016244 alc861_auto_init_multi_out(codec);
16245 alc861_auto_init_hp_out(codec);
16246 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016247 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016248 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016249 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016250}
16251
Takashi Iwaicb53c622007-08-10 17:21:45 +020016252#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +020016253static const struct hda_amp_list alc861_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +020016254 { 0x15, HDA_INPUT, 0 },
16255 { 0x15, HDA_INPUT, 1 },
16256 { 0x15, HDA_INPUT, 2 },
16257 { 0x15, HDA_INPUT, 3 },
16258 { } /* end */
16259};
16260#endif
16261
Kailang Yangdf694da2005-12-05 19:42:22 +010016262
16263/*
16264 * configuration and preset
16265 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016266static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016267 [ALC861_3ST] = "3stack",
16268 [ALC660_3ST] = "3stack-660",
16269 [ALC861_3ST_DIG] = "3stack-dig",
16270 [ALC861_6ST_DIG] = "6stack-dig",
16271 [ALC861_UNIWILL_M31] = "uniwill-m31",
16272 [ALC861_TOSHIBA] = "toshiba",
16273 [ALC861_ASUS] = "asus",
16274 [ALC861_ASUS_LAPTOP] = "asus-laptop",
16275 [ALC861_AUTO] = "auto",
16276};
16277
Takashi Iwaia9111322011-05-02 11:30:18 +020016278static const struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010016279 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016280 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16281 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16282 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016283 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016284 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016285 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016286 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16287 * Any other models that need this preset?
16288 */
16289 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016290 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16291 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016292 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16293 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16294 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16295 /* FIXME: the below seems conflict */
16296 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16297 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16298 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016299 {}
16300};
16301
Takashi Iwaia9111322011-05-02 11:30:18 +020016302static const struct alc_config_preset alc861_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010016303 [ALC861_3ST] = {
16304 .mixers = { alc861_3ST_mixer },
16305 .init_verbs = { alc861_threestack_init_verbs },
16306 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16307 .dac_nids = alc861_dac_nids,
16308 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16309 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016310 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016311 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16312 .adc_nids = alc861_adc_nids,
16313 .input_mux = &alc861_capture_source,
16314 },
16315 [ALC861_3ST_DIG] = {
16316 .mixers = { alc861_base_mixer },
16317 .init_verbs = { alc861_threestack_init_verbs },
16318 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16319 .dac_nids = alc861_dac_nids,
16320 .dig_out_nid = ALC861_DIGOUT_NID,
16321 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16322 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016323 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016324 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16325 .adc_nids = alc861_adc_nids,
16326 .input_mux = &alc861_capture_source,
16327 },
16328 [ALC861_6ST_DIG] = {
16329 .mixers = { alc861_base_mixer },
16330 .init_verbs = { alc861_base_init_verbs },
16331 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16332 .dac_nids = alc861_dac_nids,
16333 .dig_out_nid = ALC861_DIGOUT_NID,
16334 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
16335 .channel_mode = alc861_8ch_modes,
16336 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16337 .adc_nids = alc861_adc_nids,
16338 .input_mux = &alc861_capture_source,
16339 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016340 [ALC660_3ST] = {
16341 .mixers = { alc861_3ST_mixer },
16342 .init_verbs = { alc861_threestack_init_verbs },
16343 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16344 .dac_nids = alc660_dac_nids,
16345 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16346 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016347 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016348 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16349 .adc_nids = alc861_adc_nids,
16350 .input_mux = &alc861_capture_source,
16351 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016352 [ALC861_UNIWILL_M31] = {
16353 .mixers = { alc861_uniwill_m31_mixer },
16354 .init_verbs = { alc861_uniwill_m31_init_verbs },
16355 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16356 .dac_nids = alc861_dac_nids,
16357 .dig_out_nid = ALC861_DIGOUT_NID,
16358 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16359 .channel_mode = alc861_uniwill_m31_modes,
16360 .need_dac_fix = 1,
16361 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16362 .adc_nids = alc861_adc_nids,
16363 .input_mux = &alc861_capture_source,
16364 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016365 [ALC861_TOSHIBA] = {
16366 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016367 .init_verbs = { alc861_base_init_verbs,
16368 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016369 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16370 .dac_nids = alc861_dac_nids,
16371 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16372 .channel_mode = alc883_3ST_2ch_modes,
16373 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16374 .adc_nids = alc861_adc_nids,
16375 .input_mux = &alc861_capture_source,
16376 .unsol_event = alc861_toshiba_unsol_event,
16377 .init_hook = alc861_toshiba_automute,
16378 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016379 [ALC861_ASUS] = {
16380 .mixers = { alc861_asus_mixer },
16381 .init_verbs = { alc861_asus_init_verbs },
16382 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16383 .dac_nids = alc861_dac_nids,
16384 .dig_out_nid = ALC861_DIGOUT_NID,
16385 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16386 .channel_mode = alc861_asus_modes,
16387 .need_dac_fix = 1,
16388 .hp_nid = 0x06,
16389 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16390 .adc_nids = alc861_adc_nids,
16391 .input_mux = &alc861_capture_source,
16392 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016393 [ALC861_ASUS_LAPTOP] = {
16394 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16395 .init_verbs = { alc861_asus_init_verbs,
16396 alc861_asus_laptop_init_verbs },
16397 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16398 .dac_nids = alc861_dac_nids,
16399 .dig_out_nid = ALC861_DIGOUT_NID,
16400 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16401 .channel_mode = alc883_3ST_2ch_modes,
16402 .need_dac_fix = 1,
16403 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16404 .adc_nids = alc861_adc_nids,
16405 .input_mux = &alc861_capture_source,
16406 },
16407};
Kailang Yangdf694da2005-12-05 19:42:22 +010016408
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016409/* Pin config fixes */
16410enum {
16411 PINFIX_FSC_AMILO_PI1505,
16412};
16413
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016414static const struct alc_fixup alc861_fixups[] = {
16415 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016416 .type = ALC_FIXUP_PINS,
16417 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016418 { 0x0b, 0x0221101f }, /* HP */
16419 { 0x0f, 0x90170310 }, /* speaker */
16420 { }
16421 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016422 },
16423};
16424
Takashi Iwaia9111322011-05-02 11:30:18 +020016425static const struct snd_pci_quirk alc861_fixup_tbl[] = {
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016426 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16427 {}
16428};
Kailang Yangdf694da2005-12-05 19:42:22 +010016429
16430static int patch_alc861(struct hda_codec *codec)
16431{
16432 struct alc_spec *spec;
16433 int board_config;
16434 int err;
16435
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016436 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016437 if (spec == NULL)
16438 return -ENOMEM;
16439
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016440 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016441
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016442 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16443 alc861_models,
16444 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016445
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016446 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016447 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16448 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016449 board_config = ALC861_AUTO;
16450 }
16451
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016452 if (board_config == ALC861_AUTO) {
16453 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
16454 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16455 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016456
Kailang Yangdf694da2005-12-05 19:42:22 +010016457 if (board_config == ALC861_AUTO) {
16458 /* automatic parse from the BIOS config */
16459 err = alc861_parse_auto_config(codec);
16460 if (err < 0) {
16461 alc_free(codec);
16462 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016463 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016464 printk(KERN_INFO
16465 "hda_codec: Cannot set up configuration "
16466 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016467 board_config = ALC861_3ST_DIG;
16468 }
16469 }
16470
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016471 err = snd_hda_attach_beep_device(codec, 0x23);
16472 if (err < 0) {
16473 alc_free(codec);
16474 return err;
16475 }
16476
Kailang Yangdf694da2005-12-05 19:42:22 +010016477 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016478 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016479
Kailang Yangdf694da2005-12-05 19:42:22 +010016480 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16481 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16482
Kailang Yangdf694da2005-12-05 19:42:22 +010016483 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16484 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16485
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016486 if (!spec->cap_mixer)
16487 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016488 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16489
Takashi Iwai2134ea42008-01-10 16:53:55 +010016490 spec->vmaster_nid = 0x03;
16491
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016492 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016493
Kailang Yangdf694da2005-12-05 19:42:22 +010016494 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016495 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016496 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016497#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016498 spec->power_hook = alc_power_eapd;
16499#endif
16500 }
16501#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016502 if (!spec->loopback.amplist)
16503 spec->loopback.amplist = alc861_loopbacks;
16504#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016505
Kailang Yangdf694da2005-12-05 19:42:22 +010016506 return 0;
16507}
16508
16509/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016510 * ALC861-VD support
16511 *
16512 * Based on ALC882
16513 *
16514 * In addition, an independent DAC
16515 */
16516#define ALC861VD_DIGOUT_NID 0x06
16517
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016518static const hda_nid_t alc861vd_dac_nids[4] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016519 /* front, surr, clfe, side surr */
16520 0x02, 0x03, 0x04, 0x05
16521};
16522
16523/* dac_nids for ALC660vd are in a different order - according to
16524 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016525 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016526 * of ALC660vd codecs, but for now there is only 3stack mixer
16527 * - and it is the same as in 861vd.
16528 * adc_nids in ALC660vd are (is) the same as in 861vd
16529 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016530static const hda_nid_t alc660vd_dac_nids[3] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016531 /* front, rear, clfe, rear_surr */
16532 0x02, 0x04, 0x03
16533};
16534
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016535static const hda_nid_t alc861vd_adc_nids[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016536 /* ADC0 */
16537 0x09,
16538};
16539
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016540static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010016541
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016542/* input MUX */
16543/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020016544static const struct hda_input_mux alc861vd_capture_source = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016545 .num_items = 4,
16546 .items = {
16547 { "Mic", 0x0 },
16548 { "Front Mic", 0x1 },
16549 { "Line", 0x2 },
16550 { "CD", 0x4 },
16551 },
16552};
16553
Takashi Iwaia9111322011-05-02 11:30:18 +020016554static const struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016555 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016556 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010016557 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010016558 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016559 },
16560};
16561
Takashi Iwaia9111322011-05-02 11:30:18 +020016562static const struct hda_input_mux alc861vd_hp_capture_source = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016563 .num_items = 2,
16564 .items = {
16565 { "Front Mic", 0x0 },
16566 { "ATAPI Mic", 0x1 },
16567 },
16568};
16569
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016570/*
16571 * 2ch mode
16572 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016573static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016574 { 2, NULL }
16575};
16576
16577/*
16578 * 6ch mode
16579 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016580static const struct hda_verb alc861vd_6stack_ch6_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016581 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16582 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16583 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16584 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16585 { } /* end */
16586};
16587
16588/*
16589 * 8ch mode
16590 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016591static const struct hda_verb alc861vd_6stack_ch8_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016592 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16593 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16594 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16595 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16596 { } /* end */
16597};
16598
Takashi Iwaia9111322011-05-02 11:30:18 +020016599static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016600 { 6, alc861vd_6stack_ch6_init },
16601 { 8, alc861vd_6stack_ch8_init },
16602};
16603
Takashi Iwaia9111322011-05-02 11:30:18 +020016604static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016605 {
16606 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16607 .name = "Channel Mode",
16608 .info = alc_ch_mode_info,
16609 .get = alc_ch_mode_get,
16610 .put = alc_ch_mode_put,
16611 },
16612 { } /* end */
16613};
16614
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016615/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16616 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16617 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016618static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016619 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16620 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16621
16622 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16623 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16624
16625 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16626 HDA_OUTPUT),
16627 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16628 HDA_OUTPUT),
16629 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16630 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16631
16632 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16633 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16634
16635 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16636
David Henningsson5f99f862011-01-04 15:24:24 +010016637 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016638 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16639 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16640
David Henningsson5f99f862011-01-04 15:24:24 +010016641 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016642 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16643 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16644
16645 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16646 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16647
16648 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16649 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16650
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016651 { } /* end */
16652};
16653
Takashi Iwaia9111322011-05-02 11:30:18 +020016654static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016655 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16656 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16657
16658 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16659
David Henningsson5f99f862011-01-04 15:24:24 +010016660 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016661 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16662 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16663
David Henningsson5f99f862011-01-04 15:24:24 +010016664 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016665 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16666 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16667
16668 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16669 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16670
16671 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16672 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16673
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016674 { } /* end */
16675};
16676
Takashi Iwaia9111322011-05-02 11:30:18 +020016677static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016678 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16679 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16680 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16681
16682 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16683
David Henningsson5f99f862011-01-04 15:24:24 +010016684 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016685 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16686 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16687
David Henningsson5f99f862011-01-04 15:24:24 +010016688 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016689 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16690 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16691
16692 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16693 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16694
16695 { } /* end */
16696};
16697
Tobin Davisb419f342008-03-07 11:57:51 +010016698/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016699 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016700 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016701static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016702 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16703 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016704 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16705 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016706 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016707 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16708 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016709 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016710 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16711 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016712 { } /* end */
16713};
16714
Kailang Yangd1a991a2007-08-15 16:21:59 +020016715/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16716 * Front Mic=0x18, ATAPI Mic = 0x19,
16717 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016718static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016719 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16720 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16721 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16722 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16723 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16724 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16725 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16726 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016727
Kailang Yangd1a991a2007-08-15 16:21:59 +020016728 { } /* end */
16729};
16730
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016731/*
16732 * generic initialization of ADC, input mixers and output mixers
16733 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016734static const struct hda_verb alc861vd_volume_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016735 /*
16736 * Unmute ADC0 and set the default input to mic-in
16737 */
16738 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16739 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16740
16741 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16742 * the analog-loopback mixer widget
16743 */
16744 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016745 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16746 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16747 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16748 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016750
16751 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016752 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16753 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16754 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016755 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016756
16757 /*
16758 * Set up output mixers (0x02 - 0x05)
16759 */
16760 /* set vol=0 to output mixers */
16761 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16762 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16763 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16764 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16765
16766 /* set up input amps for analog loopback */
16767 /* Amp Indices: DAC = 0, mixer = 1 */
16768 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16769 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16770 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16771 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16772 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16773 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16774 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16775 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16776
16777 { }
16778};
16779
16780/*
16781 * 3-stack pin configuration:
16782 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16783 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016784static const struct hda_verb alc861vd_3stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016785 /*
16786 * Set pin mode and muting
16787 */
16788 /* set front pin widgets 0x14 for output */
16789 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16790 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16791 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16792
16793 /* Mic (rear) pin: input vref at 80% */
16794 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16795 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16796 /* Front Mic pin: input vref at 80% */
16797 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16798 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16799 /* Line In pin: input */
16800 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16801 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16802 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16803 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16804 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16805 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16806 /* CD pin widget for input */
16807 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16808
16809 { }
16810};
16811
16812/*
16813 * 6-stack pin configuration:
16814 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016815static const struct hda_verb alc861vd_6stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016816 /*
16817 * Set pin mode and muting
16818 */
16819 /* set front pin widgets 0x14 for output */
16820 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16821 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16822 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16823
16824 /* Rear Pin: output 1 (0x0d) */
16825 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16826 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16827 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16828 /* CLFE Pin: output 2 (0x0e) */
16829 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16831 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16832 /* Side Pin: output 3 (0x0f) */
16833 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16834 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16835 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16836
16837 /* Mic (rear) pin: input vref at 80% */
16838 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16839 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16840 /* Front Mic pin: input vref at 80% */
16841 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16842 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16843 /* Line In pin: input */
16844 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16845 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16846 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16847 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16848 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16849 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16850 /* CD pin widget for input */
16851 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16852
16853 { }
16854};
16855
Takashi Iwaia9111322011-05-02 11:30:18 +020016856static const struct hda_verb alc861vd_eapd_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016857 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16858 { }
16859};
16860
Takashi Iwaia9111322011-05-02 11:30:18 +020016861static const struct hda_verb alc660vd_eapd_verbs[] = {
Kailang Yangf9423e72008-05-27 12:32:25 +020016862 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16863 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16864 { }
16865};
16866
Takashi Iwaia9111322011-05-02 11:30:18 +020016867static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016868 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16869 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16870 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16871 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016872 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016873 {}
16874};
16875
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016876static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016877{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016878 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016879 spec->autocfg.hp_pins[0] = 0x1b;
16880 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016881 spec->automute = 1;
16882 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016883}
16884
16885static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16886{
Takashi Iwaid922b512011-04-28 12:18:53 +020016887 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016888 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016889}
16890
16891static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16892 unsigned int res)
16893{
16894 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016895 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016896 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016897 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016898 default:
Takashi Iwaid922b512011-04-28 12:18:53 +020016899 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016900 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016901 }
16902}
16903
Takashi Iwaia9111322011-05-02 11:30:18 +020016904static const struct hda_verb alc861vd_dallas_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020016905 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16906 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16907 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16908 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16909
16910 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16911 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16912 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16913 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16914 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16915 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16916 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16917 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016918
Kailang Yang272a5272007-05-14 11:00:38 +020016919 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16920 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16921 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16922 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16923 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16924 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16925 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16926 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16927
16928 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16929 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16930 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16931 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16932 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16933 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16934 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16935 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16936
16937 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16938 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16939 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16940 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16941
16942 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016943 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016944 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16945
16946 { } /* end */
16947};
16948
16949/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016950static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016951{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016952 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016953
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016954 spec->autocfg.hp_pins[0] = 0x15;
16955 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016956 spec->automute = 1;
16957 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +020016958}
16959
Takashi Iwaicb53c622007-08-10 17:21:45 +020016960#ifdef CONFIG_SND_HDA_POWER_SAVE
16961#define alc861vd_loopbacks alc880_loopbacks
16962#endif
16963
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016964/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016965#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16966#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16967#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16968#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16969
16970/*
16971 * configuration and preset
16972 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016973static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016974 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016975 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016976 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016977 [ALC861VD_3ST] = "3stack",
16978 [ALC861VD_3ST_DIG] = "3stack-digout",
16979 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016980 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016981 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016982 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016983 [ALC861VD_AUTO] = "auto",
16984};
16985
Takashi Iwaia9111322011-05-02 11:30:18 +020016986static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016987 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16988 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016989 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016990 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016991 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016992 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016993 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016994 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016995 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016996 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016997 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016998 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016999 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017000 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020017001 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017002 {}
17003};
17004
Takashi Iwaia9111322011-05-02 11:30:18 +020017005static const struct alc_config_preset alc861vd_presets[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017006 [ALC660VD_3ST] = {
17007 .mixers = { alc861vd_3st_mixer },
17008 .init_verbs = { alc861vd_volume_init_verbs,
17009 alc861vd_3stack_init_verbs },
17010 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17011 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017012 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17013 .channel_mode = alc861vd_3stack_2ch_modes,
17014 .input_mux = &alc861vd_capture_source,
17015 },
Mike Crash6963f842007-06-25 12:12:51 +020017016 [ALC660VD_3ST_DIG] = {
17017 .mixers = { alc861vd_3st_mixer },
17018 .init_verbs = { alc861vd_volume_init_verbs,
17019 alc861vd_3stack_init_verbs },
17020 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17021 .dac_nids = alc660vd_dac_nids,
17022 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020017023 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17024 .channel_mode = alc861vd_3stack_2ch_modes,
17025 .input_mux = &alc861vd_capture_source,
17026 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017027 [ALC861VD_3ST] = {
17028 .mixers = { alc861vd_3st_mixer },
17029 .init_verbs = { alc861vd_volume_init_verbs,
17030 alc861vd_3stack_init_verbs },
17031 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17032 .dac_nids = alc861vd_dac_nids,
17033 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17034 .channel_mode = alc861vd_3stack_2ch_modes,
17035 .input_mux = &alc861vd_capture_source,
17036 },
17037 [ALC861VD_3ST_DIG] = {
17038 .mixers = { alc861vd_3st_mixer },
17039 .init_verbs = { alc861vd_volume_init_verbs,
17040 alc861vd_3stack_init_verbs },
17041 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17042 .dac_nids = alc861vd_dac_nids,
17043 .dig_out_nid = ALC861VD_DIGOUT_NID,
17044 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17045 .channel_mode = alc861vd_3stack_2ch_modes,
17046 .input_mux = &alc861vd_capture_source,
17047 },
17048 [ALC861VD_6ST_DIG] = {
17049 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
17050 .init_verbs = { alc861vd_volume_init_verbs,
17051 alc861vd_6stack_init_verbs },
17052 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17053 .dac_nids = alc861vd_dac_nids,
17054 .dig_out_nid = ALC861VD_DIGOUT_NID,
17055 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
17056 .channel_mode = alc861vd_6stack_modes,
17057 .input_mux = &alc861vd_capture_source,
17058 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020017059 [ALC861VD_LENOVO] = {
17060 .mixers = { alc861vd_lenovo_mixer },
17061 .init_verbs = { alc861vd_volume_init_verbs,
17062 alc861vd_3stack_init_verbs,
17063 alc861vd_eapd_verbs,
17064 alc861vd_lenovo_unsol_verbs },
17065 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17066 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017067 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17068 .channel_mode = alc861vd_3stack_2ch_modes,
17069 .input_mux = &alc861vd_capture_source,
17070 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017071 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017072 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017073 },
Kailang Yang272a5272007-05-14 11:00:38 +020017074 [ALC861VD_DALLAS] = {
17075 .mixers = { alc861vd_dallas_mixer },
17076 .init_verbs = { alc861vd_dallas_verbs },
17077 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17078 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020017079 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17080 .channel_mode = alc861vd_3stack_2ch_modes,
17081 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020017082 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017083 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020017084 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017085 },
17086 [ALC861VD_HP] = {
17087 .mixers = { alc861vd_hp_mixer },
17088 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
17089 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17090 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017091 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017092 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17093 .channel_mode = alc861vd_3stack_2ch_modes,
17094 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020017095 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017096 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020017097 .init_hook = alc_hp_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020017098 },
Takashi Iwai13c94742008-11-05 08:06:08 +010017099 [ALC660VD_ASUS_V1S] = {
17100 .mixers = { alc861vd_lenovo_mixer },
17101 .init_verbs = { alc861vd_volume_init_verbs,
17102 alc861vd_3stack_init_verbs,
17103 alc861vd_eapd_verbs,
17104 alc861vd_lenovo_unsol_verbs },
17105 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17106 .dac_nids = alc660vd_dac_nids,
17107 .dig_out_nid = ALC861VD_DIGOUT_NID,
17108 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17109 .channel_mode = alc861vd_3stack_2ch_modes,
17110 .input_mux = &alc861vd_capture_source,
17111 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017112 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017113 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010017114 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017115};
17116
17117/*
17118 * BIOS auto configuration
17119 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020017120static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
17121 const struct auto_pin_cfg *cfg)
17122{
Herton Ronaldo Krzesinski71675942010-11-25 00:08:01 -020017123 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020017124}
17125
17126
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017127static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
17128 hda_nid_t nid, int pin_type, int dac_idx)
17129{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017130 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017131}
17132
17133static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
17134{
17135 struct alc_spec *spec = codec->spec;
17136 int i;
17137
17138 for (i = 0; i <= HDA_SIDE; i++) {
17139 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017140 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017141 if (nid)
17142 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017143 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017144 }
17145}
17146
17147
17148static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
17149{
17150 struct alc_spec *spec = codec->spec;
17151 hda_nid_t pin;
17152
17153 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017154 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017155 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017156 pin = spec->autocfg.speaker_pins[0];
17157 if (pin)
17158 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017159}
17160
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017161#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
17162
17163static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
17164{
17165 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017166 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017167 int i;
17168
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017169 for (i = 0; i < cfg->num_inputs; i++) {
17170 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017171 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020017172 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010017173 if (nid != ALC861VD_PIN_CD_NID &&
17174 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017175 snd_hda_codec_write(codec, nid, 0,
17176 AC_VERB_SET_AMP_GAIN_MUTE,
17177 AMP_OUT_MUTE);
17178 }
17179 }
17180}
17181
Takashi Iwaif511b012008-08-15 16:46:42 +020017182#define alc861vd_auto_init_input_src alc882_auto_init_input_src
17183
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017184#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
17185#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
17186
17187/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010017188/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017189 * different NIDs for mute/unmute switch and volume control */
17190static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
17191 const struct auto_pin_cfg *cfg)
17192{
Takashi Iwaiea734962011-01-17 11:29:34 +010017193 static const char * const chname[4] = {
17194 "Front", "Surround", "CLFE", "Side"
17195 };
Takashi Iwaice764ab2011-04-27 16:35:23 +020017196 const char *pfx = alc_get_line_out_pfx(spec, true);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017197 hda_nid_t nid_v, nid_s;
Takashi Iwaice764ab2011-04-27 16:35:23 +020017198 int i, err, noutputs;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017199
Takashi Iwaice764ab2011-04-27 16:35:23 +020017200 noutputs = cfg->line_outs;
17201 if (spec->multi_ios > 0)
17202 noutputs += spec->multi_ios;
17203
17204 for (i = 0; i < noutputs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017205 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017206 continue;
17207 nid_v = alc861vd_idx_to_mixer_vol(
17208 alc880_dac_to_idx(
17209 spec->multiout.dac_nids[i]));
17210 nid_s = alc861vd_idx_to_mixer_switch(
17211 alc880_dac_to_idx(
17212 spec->multiout.dac_nids[i]));
17213
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017214 if (!pfx && i == 2) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017215 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017216 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17217 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017218 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
17219 HDA_OUTPUT));
17220 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017221 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017222 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17223 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017224 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
17225 HDA_OUTPUT));
17226 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017227 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017228 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17229 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017230 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
17231 HDA_INPUT));
17232 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017233 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017234 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17235 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017236 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
17237 HDA_INPUT));
17238 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017239 return err;
17240 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017241 const char *name = pfx;
David Henningsson5a882642011-03-23 08:35:07 +010017242 int index = i;
17243 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017244 name = chname[i];
David Henningsson5a882642011-03-23 08:35:07 +010017245 index = 0;
17246 }
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017247 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson5a882642011-03-23 08:35:07 +010017248 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017249 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
17250 HDA_OUTPUT));
17251 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017252 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017253 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson5a882642011-03-23 08:35:07 +010017254 name, index,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017255 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017256 HDA_INPUT));
17257 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017258 return err;
17259 }
17260 }
17261 return 0;
17262}
17263
17264/* add playback controls for speaker and HP outputs */
17265/* Based on ALC880 version. But ALC861VD has separate,
17266 * different NIDs for mute/unmute switch and volume control */
17267static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
17268 hda_nid_t pin, const char *pfx)
17269{
17270 hda_nid_t nid_v, nid_s;
17271 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017272
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017273 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017274 return 0;
17275
17276 if (alc880_is_fixed_pin(pin)) {
17277 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17278 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017279 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017280 spec->multiout.hp_nid = nid_v;
17281 else
17282 spec->multiout.extra_out_nid[0] = nid_v;
17283 /* control HP volume/switch on the output mixer amp */
17284 nid_v = alc861vd_idx_to_mixer_vol(
17285 alc880_fixed_pin_idx(pin));
17286 nid_s = alc861vd_idx_to_mixer_switch(
17287 alc880_fixed_pin_idx(pin));
17288
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017289 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017290 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17291 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017292 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017293 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017294 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17295 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017296 return err;
17297 } else if (alc880_is_multi_pin(pin)) {
17298 /* set manual connection */
17299 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017300 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017301 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17302 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017303 return err;
17304 }
17305 return 0;
17306}
17307
17308/* parse the BIOS configuration and set up the alc_spec
17309 * return 1 if successful, 0 if the proper config is not found,
17310 * or a negative error code
17311 * Based on ALC880 version - had to change it to override
17312 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17313static int alc861vd_parse_auto_config(struct hda_codec *codec)
17314{
17315 struct alc_spec *spec = codec->spec;
17316 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017317 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017318
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017319 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17320 alc861vd_ignore);
17321 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017322 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017323 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017324 return 0; /* can't find valid BIOS pin config */
17325
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017326 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17327 if (err < 0)
17328 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020017329 err = alc_auto_add_multi_channel_mode(codec);
17330 if (err < 0)
17331 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017332 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17333 if (err < 0)
17334 return err;
17335 err = alc861vd_auto_create_extra_out(spec,
17336 spec->autocfg.speaker_pins[0],
17337 "Speaker");
17338 if (err < 0)
17339 return err;
17340 err = alc861vd_auto_create_extra_out(spec,
17341 spec->autocfg.hp_pins[0],
17342 "Headphone");
17343 if (err < 0)
17344 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017345 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017346 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017347 return err;
17348
17349 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17350
Takashi Iwai757899a2010-07-30 10:48:14 +020017351 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017352
Takashi Iwai603c4012008-07-30 15:01:44 +020017353 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017354 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017355
Takashi Iwaid88897e2008-10-31 15:01:37 +010017356 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017357
17358 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017359 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017360
Takashi Iwai776e1842007-08-29 15:07:11 +020017361 err = alc_auto_add_mic_boost(codec);
17362 if (err < 0)
17363 return err;
17364
Kailang Yang6227cdc2010-02-25 08:36:52 +010017365 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017366
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017367 return 1;
17368}
17369
17370/* additional initialization for auto-configuration model */
17371static void alc861vd_auto_init(struct hda_codec *codec)
17372{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017373 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017374 alc861vd_auto_init_multi_out(codec);
17375 alc861vd_auto_init_hp_out(codec);
17376 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017377 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017378 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017379 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017380 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017381}
17382
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017383enum {
17384 ALC660VD_FIX_ASUS_GPIO1
17385};
17386
17387/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017388static const struct alc_fixup alc861vd_fixups[] = {
17389 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017390 .type = ALC_FIXUP_VERBS,
17391 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020017392 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17393 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17394 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17395 { }
17396 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017397 },
17398};
17399
Takashi Iwaia9111322011-05-02 11:30:18 +020017400static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017401 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17402 {}
17403};
17404
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017405static int patch_alc861vd(struct hda_codec *codec)
17406{
17407 struct alc_spec *spec;
17408 int err, board_config;
17409
17410 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17411 if (spec == NULL)
17412 return -ENOMEM;
17413
17414 codec->spec = spec;
17415
17416 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17417 alc861vd_models,
17418 alc861vd_cfg_tbl);
17419
17420 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017421 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17422 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017423 board_config = ALC861VD_AUTO;
17424 }
17425
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017426 if (board_config == ALC861VD_AUTO) {
17427 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
17428 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
17429 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017430
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017431 if (board_config == ALC861VD_AUTO) {
17432 /* automatic parse from the BIOS config */
17433 err = alc861vd_parse_auto_config(codec);
17434 if (err < 0) {
17435 alc_free(codec);
17436 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017437 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017438 printk(KERN_INFO
17439 "hda_codec: Cannot set up configuration "
17440 "from BIOS. Using base mode...\n");
17441 board_config = ALC861VD_3ST;
17442 }
17443 }
17444
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017445 err = snd_hda_attach_beep_device(codec, 0x23);
17446 if (err < 0) {
17447 alc_free(codec);
17448 return err;
17449 }
17450
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017451 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017452 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017453
Kailang Yang2f893282008-05-27 12:14:47 +020017454 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017455 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017456 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017457 }
17458
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017459 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17460 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17461
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017462 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17463 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17464
Takashi Iwaidd704692009-08-11 08:45:11 +020017465 if (!spec->adc_nids) {
17466 spec->adc_nids = alc861vd_adc_nids;
17467 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17468 }
17469 if (!spec->capsrc_nids)
17470 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017471
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017472 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017473 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017474
Takashi Iwai2134ea42008-01-10 16:53:55 +010017475 spec->vmaster_nid = 0x02;
17476
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017477 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017478
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017479 codec->patch_ops = alc_patch_ops;
17480
17481 if (board_config == ALC861VD_AUTO)
17482 spec->init_hook = alc861vd_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020017483 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017484#ifdef CONFIG_SND_HDA_POWER_SAVE
17485 if (!spec->loopback.amplist)
17486 spec->loopback.amplist = alc861vd_loopbacks;
17487#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017488
17489 return 0;
17490}
17491
17492/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017493 * ALC662 support
17494 *
17495 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17496 * configuration. Each pin widget can choose any input DACs and a mixer.
17497 * Each ADC is connected from a mixer of all inputs. This makes possible
17498 * 6-channel independent captures.
17499 *
17500 * In addition, an independent DAC for the multi-playback (not used in this
17501 * driver yet).
17502 */
17503#define ALC662_DIGOUT_NID 0x06
17504#define ALC662_DIGIN_NID 0x0a
17505
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017506static const hda_nid_t alc662_dac_nids[3] = {
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080017507 /* front, rear, clfe */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017508 0x02, 0x03, 0x04
17509};
17510
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017511static const hda_nid_t alc272_dac_nids[2] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017512 0x02, 0x03
17513};
17514
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017515static const hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017516 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017517 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017518};
Takashi Iwaie1406342008-02-11 18:32:32 +010017519
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017520static const hda_nid_t alc272_adc_nids[1] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017521 /* ADC1-2 */
17522 0x08,
17523};
17524
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017525static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
17526static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017527
Takashi Iwaie1406342008-02-11 18:32:32 +010017528
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017529/* input MUX */
17530/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020017531static const struct hda_input_mux alc662_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017532 .num_items = 4,
17533 .items = {
17534 { "Mic", 0x0 },
17535 { "Front Mic", 0x1 },
17536 { "Line", 0x2 },
17537 { "CD", 0x4 },
17538 },
17539};
17540
Takashi Iwaia9111322011-05-02 11:30:18 +020017541static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017542 .num_items = 2,
17543 .items = {
17544 { "Mic", 0x1 },
17545 { "Line", 0x2 },
17546 },
17547};
Kailang Yang291702f2007-10-16 14:28:03 +020017548
Takashi Iwaia9111322011-05-02 11:30:18 +020017549static const struct hda_input_mux alc663_capture_source = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017550 .num_items = 3,
17551 .items = {
17552 { "Mic", 0x0 },
17553 { "Front Mic", 0x1 },
17554 { "Line", 0x2 },
17555 },
17556};
17557
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017558#if 0 /* set to 1 for testing other input sources below */
Takashi Iwaia9111322011-05-02 11:30:18 +020017559static const struct hda_input_mux alc272_nc10_capture_source = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020017560 .num_items = 16,
17561 .items = {
17562 { "Autoselect Mic", 0x0 },
17563 { "Internal Mic", 0x1 },
17564 { "In-0x02", 0x2 },
17565 { "In-0x03", 0x3 },
17566 { "In-0x04", 0x4 },
17567 { "In-0x05", 0x5 },
17568 { "In-0x06", 0x6 },
17569 { "In-0x07", 0x7 },
17570 { "In-0x08", 0x8 },
17571 { "In-0x09", 0x9 },
17572 { "In-0x0a", 0x0a },
17573 { "In-0x0b", 0x0b },
17574 { "In-0x0c", 0x0c },
17575 { "In-0x0d", 0x0d },
17576 { "In-0x0e", 0x0e },
17577 { "In-0x0f", 0x0f },
17578 },
17579};
17580#endif
17581
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017582/*
17583 * 2ch mode
17584 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017585static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017586 { 2, NULL }
17587};
17588
17589/*
17590 * 2ch mode
17591 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017592static const struct hda_verb alc662_3ST_ch2_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017593 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17594 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17595 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17596 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17597 { } /* end */
17598};
17599
17600/*
17601 * 6ch mode
17602 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017603static const struct hda_verb alc662_3ST_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017604 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17605 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17606 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17607 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17608 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17609 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17610 { } /* end */
17611};
17612
Takashi Iwaia9111322011-05-02 11:30:18 +020017613static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017614 { 2, alc662_3ST_ch2_init },
17615 { 6, alc662_3ST_ch6_init },
17616};
17617
17618/*
17619 * 2ch mode
17620 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017621static const struct hda_verb alc662_sixstack_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017622 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17623 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17624 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17625 { } /* end */
17626};
17627
17628/*
17629 * 6ch mode
17630 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017631static const struct hda_verb alc662_sixstack_ch8_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017632 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17633 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17634 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17635 { } /* end */
17636};
17637
Takashi Iwaia9111322011-05-02 11:30:18 +020017638static const struct hda_channel_mode alc662_5stack_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017639 { 2, alc662_sixstack_ch6_init },
17640 { 6, alc662_sixstack_ch8_init },
17641};
17642
17643/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17644 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17645 */
17646
Takashi Iwaia9111322011-05-02 11:30:18 +020017647static const struct snd_kcontrol_new alc662_base_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017648 /* output mixer control */
17649 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017650 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017651 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017652 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017653 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17654 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017655 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17656 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017657 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17658
17659 /*Input mixer control */
17660 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17661 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17662 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17663 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17664 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17665 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17666 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17667 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017668 { } /* end */
17669};
17670
Takashi Iwaia9111322011-05-02 11:30:18 +020017671static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017672 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017673 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17675 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17676 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17677 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17678 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17679 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17680 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17681 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17682 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017683 { } /* end */
17684};
17685
Takashi Iwaia9111322011-05-02 11:30:18 +020017686static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017687 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017688 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017689 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017690 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017691 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17692 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017693 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17694 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017695 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17696 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17697 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17698 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17699 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17700 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17701 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17702 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17703 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017704 { } /* end */
17705};
17706
Takashi Iwaia9111322011-05-02 11:30:18 +020017707static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017708 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17709 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017710 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17711 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017712 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17713 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17714 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17715 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17716 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017717 { } /* end */
17718};
17719
Takashi Iwaia9111322011-05-02 11:30:18 +020017720static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017721 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17722 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017723
David Henningsson5f99f862011-01-04 15:24:24 +010017724 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017725 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17726 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017727
David Henningsson5f99f862011-01-04 15:24:24 +010017728 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017729 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17730 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017731 { } /* end */
17732};
17733
Takashi Iwaia9111322011-05-02 11:30:18 +020017734static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017735 ALC262_HIPPO_MASTER_SWITCH,
17736 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017737 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017738 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17739 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017740 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17741 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17742 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17743 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17744 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17745 { } /* end */
17746};
17747
Takashi Iwaia9111322011-05-02 11:30:18 +020017748static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017749 .ops = &snd_hda_bind_vol,
17750 .values = {
17751 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17752 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17753 0
17754 },
17755};
17756
Takashi Iwaia9111322011-05-02 11:30:18 +020017757static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017758 .ops = &snd_hda_bind_sw,
17759 .values = {
17760 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17761 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17762 0
17763 },
17764};
17765
Takashi Iwaia9111322011-05-02 11:30:18 +020017766static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017767 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17768 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17769 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17770 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17771 { } /* end */
17772};
17773
Takashi Iwaia9111322011-05-02 11:30:18 +020017774static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017775 .ops = &snd_hda_bind_sw,
17776 .values = {
17777 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17778 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17779 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17780 0
17781 },
17782};
17783
Takashi Iwaia9111322011-05-02 11:30:18 +020017784static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017785 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17786 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17787 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17788 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17789 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17790 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17791
17792 { } /* end */
17793};
17794
Takashi Iwaia9111322011-05-02 11:30:18 +020017795static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017796 .ops = &snd_hda_bind_sw,
17797 .values = {
17798 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17799 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17800 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17801 0
17802 },
17803};
17804
Takashi Iwaia9111322011-05-02 11:30:18 +020017805static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017806 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17807 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17808 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17809 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17810 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17811 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17812 { } /* end */
17813};
17814
Takashi Iwaia9111322011-05-02 11:30:18 +020017815static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017816 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17817 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017818 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17819 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17820 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17821 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17822 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17823 { } /* end */
17824};
17825
Takashi Iwaia9111322011-05-02 11:30:18 +020017826static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017827 .ops = &snd_hda_bind_vol,
17828 .values = {
17829 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17830 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17831 0
17832 },
17833};
17834
Takashi Iwaia9111322011-05-02 11:30:18 +020017835static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017836 .ops = &snd_hda_bind_sw,
17837 .values = {
17838 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17839 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17840 0
17841 },
17842};
17843
Takashi Iwaia9111322011-05-02 11:30:18 +020017844static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017845 HDA_BIND_VOL("Master Playback Volume",
17846 &alc663_asus_two_bind_master_vol),
17847 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17848 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017849 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17850 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17851 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017852 { } /* end */
17853};
17854
Takashi Iwaia9111322011-05-02 11:30:18 +020017855static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017856 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17857 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17858 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17859 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17860 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17861 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017862 { } /* end */
17863};
17864
Takashi Iwaia9111322011-05-02 11:30:18 +020017865static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017866 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17867 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17868 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17869 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17870 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17871
17872 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17873 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017874 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17875 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017876 { } /* end */
17877};
17878
Takashi Iwaia9111322011-05-02 11:30:18 +020017879static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017880 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17881 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17882 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17883
17884 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17885 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017886 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17887 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017888 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17889 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17890 { } /* end */
17891};
17892
Takashi Iwaia9111322011-05-02 11:30:18 +020017893static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017894 .ops = &snd_hda_bind_sw,
17895 .values = {
17896 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17897 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17898 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17899 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17900 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17901 0
17902 },
17903};
17904
Takashi Iwaia9111322011-05-02 11:30:18 +020017905static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017906 .ops = &snd_hda_bind_sw,
17907 .values = {
17908 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17909 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17910 0
17911 },
17912};
17913
Takashi Iwaia9111322011-05-02 11:30:18 +020017914static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017915 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17916 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17917 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17918 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17919 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17920 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17921 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17922 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17923 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17924 { } /* end */
17925};
17926
Takashi Iwaia9111322011-05-02 11:30:18 +020017927static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017928 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17929 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17930 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17931 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17932 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17933 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17934 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17935 { } /* end */
17936};
17937
17938
Takashi Iwaia9111322011-05-02 11:30:18 +020017939static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017940 {
17941 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17942 .name = "Channel Mode",
17943 .info = alc_ch_mode_info,
17944 .get = alc_ch_mode_get,
17945 .put = alc_ch_mode_put,
17946 },
17947 { } /* end */
17948};
17949
Takashi Iwaia9111322011-05-02 11:30:18 +020017950static const struct hda_verb alc662_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017951 /* ADC: mute amp left and right */
17952 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17953 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017954
Kailang Yangb60dd392007-09-20 12:50:29 +020017955 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17956 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17957 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17958 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17959 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17960 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017961
17962 /* Front Pin: output 0 (0x0c) */
17963 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17964 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17965
17966 /* Rear Pin: output 1 (0x0d) */
17967 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17968 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17969
17970 /* CLFE Pin: output 2 (0x0e) */
17971 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17972 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17973
17974 /* Mic (rear) pin: input vref at 80% */
17975 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17976 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17977 /* Front Mic pin: input vref at 80% */
17978 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17979 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17980 /* Line In pin: input */
17981 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17982 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17983 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17984 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17985 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17986 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17987 /* CD pin widget for input */
17988 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17989
17990 /* FIXME: use matrix-type input source selection */
17991 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17992 /* Input mixer */
17993 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017994 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017995
Takashi Iwaia7f23712011-04-07 10:24:23 +020017996 { }
17997};
17998
Takashi Iwaia9111322011-05-02 11:30:18 +020017999static const struct hda_verb alc662_eapd_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020018000 /* always trun on EAPD */
18001 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
18002 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018003 { }
18004};
18005
Takashi Iwaia9111322011-05-02 11:30:18 +020018006static const struct hda_verb alc662_sue_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018007 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
18008 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020018009 {}
18010};
18011
Takashi Iwaia9111322011-05-02 11:30:18 +020018012static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020018013 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18014 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18015 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018016};
18017
Kailang Yang8c427222008-01-10 13:03:59 +010018018/* Set Unsolicited Event*/
Takashi Iwaia9111322011-05-02 11:30:18 +020018019static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010018020 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18021 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18022 {}
18023};
18024
Takashi Iwaia9111322011-05-02 11:30:18 +020018025static const struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018026 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18027 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020018028 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18029 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020018030 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18031 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020018033 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18034 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18035 {}
18036};
18037
Takashi Iwaia9111322011-05-02 11:30:18 +020018038static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018039 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18040 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18041 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18042 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18043 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18044 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18045 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18046 {}
18047};
18048
Takashi Iwaia9111322011-05-02 11:30:18 +020018049static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018050 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18051 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18052 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18053 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18054 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18055 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18056 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18057 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18058 {}
18059};
18060
Takashi Iwaia9111322011-05-02 11:30:18 +020018061static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018062 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18063 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18064 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18065 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18066 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18067 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18068 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18069 {}
18070};
18071
Takashi Iwaia9111322011-05-02 11:30:18 +020018072static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018073 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18074 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18075 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18076 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18077 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18078 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18079 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18080 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18081 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18082 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18083 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18084 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18085 {}
18086};
18087
Takashi Iwaia9111322011-05-02 11:30:18 +020018088static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018089 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18090 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18091 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18092 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18093 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18094 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18095 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18096 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18097 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18098 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18099 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18100 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18101 {}
18102};
18103
Takashi Iwaia9111322011-05-02 11:30:18 +020018104static const struct hda_verb alc663_g71v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020018105 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18106 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
18107 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
18108
18109 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18110 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18111 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18112
18113 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
18114 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
18115 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
18116 {}
18117};
18118
Takashi Iwaia9111322011-05-02 11:30:18 +020018119static const struct hda_verb alc663_g50v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020018120 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18121 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18122 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18123
18124 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18125 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18126 {}
18127};
18128
Takashi Iwaia9111322011-05-02 11:30:18 +020018129static const struct hda_verb alc662_ecs_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018130 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
18131 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18132 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18133 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18134 {}
18135};
18136
Takashi Iwaia9111322011-05-02 11:30:18 +020018137static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020018138 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18139 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18140 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18141 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18142 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18143 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18144 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18145 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18146 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18147 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18148 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18149 {}
18150};
18151
Takashi Iwaia9111322011-05-02 11:30:18 +020018152static const struct hda_verb alc272_dell_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020018153 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18154 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18155 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18156 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18157 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18158 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18159 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18160 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18161 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18162 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18163 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18164 {}
18165};
18166
Takashi Iwaia9111322011-05-02 11:30:18 +020018167static const struct hda_verb alc663_mode7_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010018168 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18169 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18170 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18171 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18172 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18173 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18174 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
18175 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18176 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18177 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18178 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18179 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18180 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18181 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18182 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18183 {}
18184};
18185
Takashi Iwaia9111322011-05-02 11:30:18 +020018186static const struct hda_verb alc663_mode8_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010018187 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18188 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18190 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
18191 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18192 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18193 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18194 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18195 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18196 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18197 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18198 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18199 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18200 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18201 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18202 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18203 {}
18204};
18205
Takashi Iwaia9111322011-05-02 11:30:18 +020018206static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018207 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
18208 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
18209 { } /* end */
18210};
18211
Takashi Iwaia9111322011-05-02 11:30:18 +020018212static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020018213 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
18214 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
18215 { } /* end */
18216};
18217
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018218static void alc662_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018219{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018220 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018221
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018222 spec->autocfg.hp_pins[0] = 0x1b;
18223 spec->autocfg.line_out_pins[0] = 0x14;
18224 spec->autocfg.speaker_pins[0] = 0x15;
18225 spec->automute = 1;
18226 spec->detect_line = 1;
18227 spec->automute_lines = 1;
18228 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018229}
18230
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018231static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020018232{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018233 struct alc_spec *spec = codec->spec;
18234
18235 alc262_hippo1_setup(codec);
18236 spec->ext_mic.pin = 0x18;
18237 spec->ext_mic.mux_idx = 0;
18238 spec->int_mic.pin = 0x19;
18239 spec->int_mic.mux_idx = 1;
18240 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018241}
18242
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018243static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018244{
Takashi Iwai42171c12009-05-08 14:11:43 +020018245 struct alc_spec *spec = codec->spec;
18246
18247 spec->autocfg.hp_pins[0] = 0x14;
18248 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaie9427962011-04-28 15:46:07 +020018249 spec->automute = 1;
18250 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang8c427222008-01-10 13:03:59 +010018251}
18252
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018253static void alc663_m51va_setup(struct hda_codec *codec)
18254{
18255 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018256 spec->autocfg.hp_pins[0] = 0x21;
18257 spec->autocfg.speaker_pins[0] = 0x14;
18258 spec->automute_mixer_nid[0] = 0x0c;
18259 spec->automute = 1;
18260 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018261 spec->ext_mic.pin = 0x18;
18262 spec->ext_mic.mux_idx = 0;
18263 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018264 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018265 spec->auto_mic = 1;
18266}
18267
Kailang Yangf1d4e282008-08-26 14:03:29 +020018268/* ***************** Mode1 ******************************/
Kailang Yangebb83ee2009-12-17 12:23:00 +010018269static void alc663_mode1_setup(struct hda_codec *codec)
18270{
18271 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018272 spec->autocfg.hp_pins[0] = 0x21;
18273 spec->autocfg.speaker_pins[0] = 0x14;
18274 spec->automute_mixer_nid[0] = 0x0c;
18275 spec->automute = 1;
18276 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018277 spec->ext_mic.pin = 0x18;
18278 spec->ext_mic.mux_idx = 0;
18279 spec->int_mic.pin = 0x19;
18280 spec->int_mic.mux_idx = 1;
18281 spec->auto_mic = 1;
18282}
18283
Kailang Yangf1d4e282008-08-26 14:03:29 +020018284/* ***************** Mode2 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018285static void alc662_mode2_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018286{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018287 struct alc_spec *spec = codec->spec;
18288 spec->autocfg.hp_pins[0] = 0x1b;
18289 spec->autocfg.speaker_pins[0] = 0x14;
18290 spec->automute = 1;
18291 spec->automute_mode = ALC_AUTOMUTE_PIN;
18292 spec->ext_mic.pin = 0x18;
18293 spec->ext_mic.mux_idx = 0;
18294 spec->int_mic.pin = 0x19;
18295 spec->int_mic.mux_idx = 1;
18296 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018297}
18298
Kailang Yangf1d4e282008-08-26 14:03:29 +020018299/* ***************** Mode3 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018300static void alc663_mode3_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018301{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018302 struct alc_spec *spec = codec->spec;
18303 spec->autocfg.hp_pins[0] = 0x21;
18304 spec->autocfg.hp_pins[0] = 0x15;
18305 spec->autocfg.speaker_pins[0] = 0x14;
18306 spec->automute = 1;
18307 spec->automute_mode = ALC_AUTOMUTE_PIN;
18308 spec->ext_mic.pin = 0x18;
18309 spec->ext_mic.mux_idx = 0;
18310 spec->int_mic.pin = 0x19;
18311 spec->int_mic.mux_idx = 1;
18312 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018313}
18314
Kailang Yangf1d4e282008-08-26 14:03:29 +020018315/* ***************** Mode4 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018316static void alc663_mode4_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018317{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018318 struct alc_spec *spec = codec->spec;
18319 spec->autocfg.hp_pins[0] = 0x21;
18320 spec->autocfg.speaker_pins[0] = 0x14;
18321 spec->autocfg.speaker_pins[1] = 0x16;
18322 spec->automute_mixer_nid[0] = 0x0c;
18323 spec->automute_mixer_nid[1] = 0x0e;
18324 spec->automute = 1;
18325 spec->automute_mode = ALC_AUTOMUTE_MIXER;
18326 spec->ext_mic.pin = 0x18;
18327 spec->ext_mic.mux_idx = 0;
18328 spec->int_mic.pin = 0x19;
18329 spec->int_mic.mux_idx = 1;
18330 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018331}
18332
Kailang Yangf1d4e282008-08-26 14:03:29 +020018333/* ***************** Mode5 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018334static void alc663_mode5_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018335{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018336 struct alc_spec *spec = codec->spec;
18337 spec->autocfg.hp_pins[0] = 0x15;
18338 spec->autocfg.speaker_pins[0] = 0x14;
18339 spec->autocfg.speaker_pins[1] = 0x16;
18340 spec->automute_mixer_nid[0] = 0x0c;
18341 spec->automute_mixer_nid[1] = 0x0e;
18342 spec->automute = 1;
18343 spec->automute_mode = ALC_AUTOMUTE_MIXER;
18344 spec->ext_mic.pin = 0x18;
18345 spec->ext_mic.mux_idx = 0;
18346 spec->int_mic.pin = 0x19;
18347 spec->int_mic.mux_idx = 1;
18348 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018349}
18350
Kailang Yangf1d4e282008-08-26 14:03:29 +020018351/* ***************** Mode6 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018352static void alc663_mode6_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018353{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018354 struct alc_spec *spec = codec->spec;
18355 spec->autocfg.hp_pins[0] = 0x1b;
18356 spec->autocfg.hp_pins[0] = 0x15;
18357 spec->autocfg.speaker_pins[0] = 0x14;
18358 spec->automute_mixer_nid[0] = 0x0c;
18359 spec->automute = 1;
18360 spec->automute_mode = ALC_AUTOMUTE_MIXER;
18361 spec->ext_mic.pin = 0x18;
18362 spec->ext_mic.mux_idx = 0;
18363 spec->int_mic.pin = 0x19;
18364 spec->int_mic.mux_idx = 1;
18365 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018366}
18367
Kailang Yangebb83ee2009-12-17 12:23:00 +010018368/* ***************** Mode7 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018369static void alc663_mode7_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010018370{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018371 struct alc_spec *spec = codec->spec;
18372 spec->autocfg.hp_pins[0] = 0x1b;
18373 spec->autocfg.hp_pins[0] = 0x21;
18374 spec->autocfg.speaker_pins[0] = 0x14;
18375 spec->autocfg.speaker_pins[0] = 0x17;
18376 spec->automute = 1;
18377 spec->automute_mode = ALC_AUTOMUTE_PIN;
18378 spec->ext_mic.pin = 0x18;
18379 spec->ext_mic.mux_idx = 0;
18380 spec->int_mic.pin = 0x19;
18381 spec->int_mic.mux_idx = 1;
18382 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018383}
18384
18385/* ***************** Mode8 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018386static void alc663_mode8_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010018387{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018388 struct alc_spec *spec = codec->spec;
18389 spec->autocfg.hp_pins[0] = 0x21;
18390 spec->autocfg.hp_pins[1] = 0x15;
18391 spec->autocfg.speaker_pins[0] = 0x14;
18392 spec->autocfg.speaker_pins[0] = 0x17;
18393 spec->automute = 1;
18394 spec->automute_mode = ALC_AUTOMUTE_PIN;
18395 spec->ext_mic.pin = 0x18;
18396 spec->ext_mic.mux_idx = 0;
18397 spec->int_mic.pin = 0x12;
18398 spec->int_mic.mux_idx = 9;
18399 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018400}
18401
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018402static void alc663_g71v_setup(struct hda_codec *codec)
Kailang Yang6dda9f42008-05-27 12:05:31 +020018403{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018404 struct alc_spec *spec = codec->spec;
18405 spec->autocfg.hp_pins[0] = 0x21;
18406 spec->autocfg.line_out_pins[0] = 0x15;
18407 spec->autocfg.speaker_pins[0] = 0x14;
18408 spec->automute = 1;
18409 spec->automute_mode = ALC_AUTOMUTE_AMP;
18410 spec->detect_line = 1;
18411 spec->automute_lines = 1;
18412 spec->ext_mic.pin = 0x18;
18413 spec->ext_mic.mux_idx = 0;
18414 spec->int_mic.pin = 0x12;
18415 spec->int_mic.mux_idx = 9;
18416 spec->auto_mic = 1;
Kailang Yang6dda9f42008-05-27 12:05:31 +020018417}
18418
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018419#define alc663_g50v_setup alc663_m51va_setup
18420
Takashi Iwaia9111322011-05-02 11:30:18 +020018421static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018422 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018423 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018424
David Henningsson5f99f862011-01-04 15:24:24 +010018425 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018426 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18427 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018428
David Henningsson5f99f862011-01-04 15:24:24 +010018429 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018430 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18431 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018432 { } /* end */
18433};
18434
Takashi Iwaia9111322011-05-02 11:30:18 +020018435static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020018436 /* Master Playback automatically created from Speaker and Headphone */
18437 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18438 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18439 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18440 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18441
David Henningsson8607f7c2010-12-20 14:43:54 +010018442 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18443 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018444 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018445
David Henningsson28c4edb2010-12-20 14:24:29 +010018446 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18447 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018448 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018449 { } /* end */
18450};
18451
Takashi Iwaicb53c622007-08-10 17:21:45 +020018452#ifdef CONFIG_SND_HDA_POWER_SAVE
18453#define alc662_loopbacks alc880_loopbacks
18454#endif
18455
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018456
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018457/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018458#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18459#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18460#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18461#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18462
18463/*
18464 * configuration and preset
18465 */
Takashi Iwaiea734962011-01-17 11:29:34 +010018466static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018467 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18468 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18469 [ALC662_3ST_6ch] = "3stack-6ch",
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080018470 [ALC662_5ST_DIG] = "5stack-dig",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018471 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018472 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018473 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018474 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018475 [ALC663_ASUS_M51VA] = "m51va",
18476 [ALC663_ASUS_G71V] = "g71v",
18477 [ALC663_ASUS_H13] = "h13",
18478 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018479 [ALC663_ASUS_MODE1] = "asus-mode1",
18480 [ALC662_ASUS_MODE2] = "asus-mode2",
18481 [ALC663_ASUS_MODE3] = "asus-mode3",
18482 [ALC663_ASUS_MODE4] = "asus-mode4",
18483 [ALC663_ASUS_MODE5] = "asus-mode5",
18484 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018485 [ALC663_ASUS_MODE7] = "asus-mode7",
18486 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018487 [ALC272_DELL] = "dell",
18488 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018489 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018490 [ALC662_AUTO] = "auto",
18491};
18492
Takashi Iwaia9111322011-05-02 11:30:18 +020018493static const struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018494 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018495 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18496 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018497 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18498 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018499 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018500 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18501 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18502 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18503 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018504 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18505 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018506 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018507 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18508 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18509 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18510 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18511 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018512 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018513 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18514 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018515 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18516 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18517 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18518 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018519 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018520 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18521 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18522 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018523 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18524 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18525 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18526 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018527 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018528 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18529 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018530 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018531 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18532 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18533 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018534 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018535 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018536 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18537 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018538 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18539 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18540 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018541 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018542 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18543 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018544 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018545 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018546 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018547 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18548 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18549 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018550 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018551 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18552 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018553 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018554 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018555 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018556 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018557 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18558 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018559 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018560 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Takashi Iwaiebb47242011-05-02 10:37:29 +020018561 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18562 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018563 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018564 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018565 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018566 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018567 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018568 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018569 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18570 ALC663_ASUS_H13),
Anisse Astier965b76d2011-02-10 13:14:44 +010018571 SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018572 {}
18573};
18574
Takashi Iwaia9111322011-05-02 11:30:18 +020018575static const struct alc_config_preset alc662_presets[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018576 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018577 .mixers = { alc662_3ST_2ch_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018578 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018579 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18580 .dac_nids = alc662_dac_nids,
18581 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018582 .dig_in_nid = ALC662_DIGIN_NID,
18583 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18584 .channel_mode = alc662_3ST_2ch_modes,
18585 .input_mux = &alc662_capture_source,
18586 },
18587 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018588 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018589 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018590 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18591 .dac_nids = alc662_dac_nids,
18592 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018593 .dig_in_nid = ALC662_DIGIN_NID,
18594 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18595 .channel_mode = alc662_3ST_6ch_modes,
18596 .need_dac_fix = 1,
18597 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018598 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018599 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018600 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018601 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018602 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18603 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018604 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18605 .channel_mode = alc662_3ST_6ch_modes,
18606 .need_dac_fix = 1,
18607 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018608 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018609 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018610 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018611 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018612 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18613 .dac_nids = alc662_dac_nids,
18614 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018615 .dig_in_nid = ALC662_DIGIN_NID,
18616 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18617 .channel_mode = alc662_5stack_modes,
18618 .input_mux = &alc662_capture_source,
18619 },
18620 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018621 .mixers = { alc662_lenovo_101e_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018622 .init_verbs = { alc662_init_verbs,
18623 alc662_eapd_init_verbs,
18624 alc662_sue_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018625 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18626 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018627 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18628 .channel_mode = alc662_3ST_2ch_modes,
18629 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018630 .unsol_event = alc_sku_unsol_event,
18631 .setup = alc662_lenovo_101e_setup,
18632 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018633 },
Kailang Yang291702f2007-10-16 14:28:03 +020018634 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018635 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018636 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018637 alc662_eapd_init_verbs,
Kailang Yang291702f2007-10-16 14:28:03 +020018638 alc662_eeepc_sue_init_verbs },
18639 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18640 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018641 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18642 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020018643 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018644 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018645 .init_hook = alc_inithook,
Kailang Yang291702f2007-10-16 14:28:03 +020018646 },
Kailang Yang8c427222008-01-10 13:03:59 +010018647 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018648 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018649 alc662_chmode_mixer },
18650 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018651 alc662_eapd_init_verbs,
Kailang Yang8c427222008-01-10 13:03:59 +010018652 alc662_eeepc_ep20_sue_init_verbs },
18653 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18654 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018655 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18656 .channel_mode = alc662_3ST_6ch_modes,
18657 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020018658 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018659 .setup = alc662_eeepc_ep20_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018660 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010018661 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018662 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018663 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018664 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018665 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018666 alc662_ecs_init_verbs },
18667 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18668 .dac_nids = alc662_dac_nids,
18669 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18670 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020018671 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018672 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018673 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018674 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018675 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018676 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018677 .init_verbs = { alc662_init_verbs,
18678 alc662_eapd_init_verbs,
18679 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018680 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18681 .dac_nids = alc662_dac_nids,
18682 .dig_out_nid = ALC662_DIGOUT_NID,
18683 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18684 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018685 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018686 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018687 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018688 },
18689 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018690 .mixers = { alc663_g71v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018691 .init_verbs = { alc662_init_verbs,
18692 alc662_eapd_init_verbs,
18693 alc663_g71v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018694 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18695 .dac_nids = alc662_dac_nids,
18696 .dig_out_nid = ALC662_DIGOUT_NID,
18697 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18698 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018699 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018700 .setup = alc663_g71v_setup,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018701 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018702 },
18703 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018704 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018705 .init_verbs = { alc662_init_verbs,
18706 alc662_eapd_init_verbs,
18707 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018708 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18709 .dac_nids = alc662_dac_nids,
18710 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18711 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018712 .setup = alc663_m51va_setup,
18713 .unsol_event = alc_sku_unsol_event,
18714 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018715 },
18716 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018717 .mixers = { alc663_g50v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018718 .init_verbs = { alc662_init_verbs,
18719 alc662_eapd_init_verbs,
18720 alc663_g50v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018721 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18722 .dac_nids = alc662_dac_nids,
18723 .dig_out_nid = ALC662_DIGOUT_NID,
18724 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18725 .channel_mode = alc662_3ST_6ch_modes,
18726 .input_mux = &alc663_capture_source,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018727 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018728 .setup = alc663_g50v_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018729 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018730 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018731 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018732 .mixers = { alc663_m51va_mixer },
18733 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018734 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018735 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018736 alc663_21jd_amic_init_verbs },
18737 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18738 .hp_nid = 0x03,
18739 .dac_nids = alc662_dac_nids,
18740 .dig_out_nid = ALC662_DIGOUT_NID,
18741 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18742 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018743 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018744 .setup = alc663_mode1_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018745 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018746 },
18747 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018748 .mixers = { alc662_1bjd_mixer },
18749 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018750 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018751 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018752 alc662_1bjd_amic_init_verbs },
18753 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18754 .dac_nids = alc662_dac_nids,
18755 .dig_out_nid = ALC662_DIGOUT_NID,
18756 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18757 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018758 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018759 .setup = alc662_mode2_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018760 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018761 },
18762 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018763 .mixers = { alc663_two_hp_m1_mixer },
18764 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018765 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018766 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018767 alc663_two_hp_amic_m1_init_verbs },
18768 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18769 .hp_nid = 0x03,
18770 .dac_nids = alc662_dac_nids,
18771 .dig_out_nid = ALC662_DIGOUT_NID,
18772 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18773 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018774 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018775 .setup = alc663_mode3_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018776 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018777 },
18778 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018779 .mixers = { alc663_asus_21jd_clfe_mixer },
18780 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018781 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018782 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018783 alc663_21jd_amic_init_verbs},
18784 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18785 .hp_nid = 0x03,
18786 .dac_nids = alc662_dac_nids,
18787 .dig_out_nid = ALC662_DIGOUT_NID,
18788 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18789 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018790 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018791 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018792 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018793 },
18794 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018795 .mixers = { alc663_asus_15jd_clfe_mixer },
18796 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018797 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018798 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018799 alc663_15jd_amic_init_verbs },
18800 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18801 .hp_nid = 0x03,
18802 .dac_nids = alc662_dac_nids,
18803 .dig_out_nid = ALC662_DIGOUT_NID,
18804 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18805 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018806 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018807 .setup = alc663_mode5_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018808 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018809 },
18810 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018811 .mixers = { alc663_two_hp_m2_mixer },
18812 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018813 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018814 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018815 alc663_two_hp_amic_m2_init_verbs },
18816 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18817 .hp_nid = 0x03,
18818 .dac_nids = alc662_dac_nids,
18819 .dig_out_nid = ALC662_DIGOUT_NID,
18820 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18821 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018822 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018823 .setup = alc663_mode6_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018824 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018825 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018826 [ALC663_ASUS_MODE7] = {
18827 .mixers = { alc663_mode7_mixer },
18828 .cap_mixer = alc662_auto_capture_mixer,
18829 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018830 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018831 alc663_mode7_init_verbs },
18832 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18833 .hp_nid = 0x03,
18834 .dac_nids = alc662_dac_nids,
18835 .dig_out_nid = ALC662_DIGOUT_NID,
18836 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18837 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018838 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018839 .setup = alc663_mode7_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018840 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018841 },
18842 [ALC663_ASUS_MODE8] = {
18843 .mixers = { alc663_mode8_mixer },
18844 .cap_mixer = alc662_auto_capture_mixer,
18845 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018846 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018847 alc663_mode8_init_verbs },
18848 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18849 .hp_nid = 0x03,
18850 .dac_nids = alc662_dac_nids,
18851 .dig_out_nid = ALC662_DIGOUT_NID,
18852 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18853 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018854 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018855 .setup = alc663_mode8_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018856 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018857 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018858 [ALC272_DELL] = {
18859 .mixers = { alc663_m51va_mixer },
18860 .cap_mixer = alc272_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018861 .init_verbs = { alc662_init_verbs,
18862 alc662_eapd_init_verbs,
18863 alc272_dell_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018864 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018865 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018866 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18867 .adc_nids = alc272_adc_nids,
18868 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18869 .capsrc_nids = alc272_capsrc_nids,
18870 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018871 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018872 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018873 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018874 },
18875 [ALC272_DELL_ZM1] = {
18876 .mixers = { alc663_m51va_mixer },
18877 .cap_mixer = alc662_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018878 .init_verbs = { alc662_init_verbs,
18879 alc662_eapd_init_verbs,
18880 alc272_dell_zm1_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018881 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018882 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018883 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18884 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018885 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018886 .capsrc_nids = alc662_capsrc_nids,
18887 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018888 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018889 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018890 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018891 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018892 [ALC272_SAMSUNG_NC10] = {
18893 .mixers = { alc272_nc10_mixer },
18894 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018895 alc662_eapd_init_verbs,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018896 alc663_21jd_amic_init_verbs },
18897 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18898 .dac_nids = alc272_dac_nids,
18899 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18900 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018901 /*.input_mux = &alc272_nc10_capture_source,*/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018902 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018903 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018904 .init_hook = alc_inithook,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018905 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018906};
18907
18908
18909/*
18910 * BIOS auto configuration
18911 */
18912
Takashi Iwai7085ec12009-10-02 09:03:58 +020018913/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018914static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018915{
Takashi Iwai604401a2011-04-27 15:14:23 +020018916 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +020018917 int i, num;
18918
18919 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
18920 for (i = 0; i < num; i++) {
18921 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
18922 return list[i];
18923 }
18924 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018925}
18926
Takashi Iwai604401a2011-04-27 15:14:23 +020018927/* go down to the selector widget before the mixer */
18928static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
18929{
18930 hda_nid_t srcs[5];
18931 int num = snd_hda_get_connections(codec, pin, srcs,
18932 ARRAY_SIZE(srcs));
18933 if (num != 1 ||
18934 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
18935 return pin;
18936 return srcs[0];
18937}
18938
Takashi Iwai7085ec12009-10-02 09:03:58 +020018939/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018940static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018941 hda_nid_t dac)
18942{
David Henningssoncc1c4522010-11-24 14:17:47 +010018943 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018944 int i, num;
18945
Takashi Iwai604401a2011-04-27 15:14:23 +020018946 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018947 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18948 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018949 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018950 return mix[i];
18951 }
18952 return 0;
18953}
18954
Takashi Iwaice764ab2011-04-27 16:35:23 +020018955/* select the connection from pin to DAC if needed */
18956static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
18957 hda_nid_t dac)
18958{
18959 hda_nid_t mix[5];
18960 int i, num;
18961
18962 pin = alc_go_down_to_selector(codec, pin);
18963 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18964 if (num < 2)
18965 return 0;
18966 for (i = 0; i < num; i++) {
18967 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
18968 snd_hda_codec_update_cache(codec, pin, 0,
18969 AC_VERB_SET_CONNECT_SEL, i);
18970 return 0;
18971 }
18972 }
18973 return 0;
18974}
18975
Takashi Iwai7085ec12009-10-02 09:03:58 +020018976/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +020018977static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018978{
18979 struct alc_spec *spec = codec->spec;
18980 hda_nid_t srcs[5];
18981 int i, j, num;
18982
Takashi Iwai604401a2011-04-27 15:14:23 +020018983 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018984 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018985 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018986 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018987 if (!nid)
18988 continue;
18989 for (j = 0; j < spec->multiout.num_dacs; j++)
18990 if (spec->multiout.dac_nids[j] == nid)
18991 break;
18992 if (j >= spec->multiout.num_dacs)
18993 return nid;
18994 }
18995 return 0;
18996}
18997
18998/* fill in the dac_nids table from the parsed pin configuration */
18999static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
19000 const struct auto_pin_cfg *cfg)
19001{
19002 struct alc_spec *spec = codec->spec;
19003 int i;
19004 hda_nid_t dac;
19005
19006 spec->multiout.dac_nids = spec->private_dac_nids;
19007 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020019008 dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019009 if (!dac)
19010 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020019011 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019012 }
19013 return 0;
19014}
19015
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019016static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
19017 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019018{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019019 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019020 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
19021}
19022
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019023static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
19024 hda_nid_t nid, int idx, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019025{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019026 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019027 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
19028}
19029
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019030#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
19031 __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
19032#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
19033 __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019034#define alc662_add_stereo_vol(spec, pfx, nid) \
19035 alc662_add_vol_ctl(spec, pfx, nid, 3)
19036#define alc662_add_stereo_sw(spec, pfx, nid) \
19037 alc662_add_sw_ctl(spec, pfx, nid, 3)
19038
19039/* add playback controls from the parsed DAC table */
19040static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
19041 const struct auto_pin_cfg *cfg)
19042{
19043 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010019044 static const char * const chname[4] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019045 "Front", "Surround", NULL /*CLFE*/, "Side"
19046 };
Takashi Iwaice764ab2011-04-27 16:35:23 +020019047 const char *pfx = alc_get_line_out_pfx(spec, true);
19048 hda_nid_t nid, mix, pin;
19049 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019050
Takashi Iwaice764ab2011-04-27 16:35:23 +020019051 noutputs = cfg->line_outs;
19052 if (spec->multi_ios > 0)
19053 noutputs += spec->multi_ios;
19054
19055 for (i = 0; i < noutputs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019056 nid = spec->multiout.dac_nids[i];
19057 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019058 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +020019059 if (i >= cfg->line_outs)
19060 pin = spec->multi_io[i - 1].pin;
19061 else
19062 pin = cfg->line_out_pins[i];
19063 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019064 if (!mix)
19065 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019066 if (!pfx && i == 2) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019067 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019068 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019069 if (err < 0)
19070 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019071 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019072 if (err < 0)
19073 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019074 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019075 if (err < 0)
19076 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019077 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019078 if (err < 0)
19079 return err;
19080 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019081 const char *name = pfx;
David Henningsson5a882642011-03-23 08:35:07 +010019082 int index = i;
19083 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019084 name = chname[i];
David Henningsson5a882642011-03-23 08:35:07 +010019085 index = 0;
19086 }
19087 err = __alc662_add_vol_ctl(spec, name, nid, index, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019088 if (err < 0)
19089 return err;
David Henningsson5a882642011-03-23 08:35:07 +010019090 err = __alc662_add_sw_ctl(spec, name, mix, index, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019091 if (err < 0)
19092 return err;
19093 }
19094 }
19095 return 0;
19096}
19097
19098/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019099/* return DAC nid if any new DAC is assigned */
19100static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019101 const char *pfx)
19102{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019103 struct alc_spec *spec = codec->spec;
19104 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019105 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019106
19107 if (!pin)
19108 return 0;
Takashi Iwai604401a2011-04-27 15:14:23 +020019109 nid = alc_auto_look_for_dac(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019110 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019111 /* the corresponding DAC is already occupied */
19112 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19113 return 0; /* no way */
19114 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019115 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019116 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19117 }
19118
Takashi Iwai604401a2011-04-27 15:14:23 +020019119 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019120 if (!mix)
19121 return 0;
19122 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19123 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019124 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019125 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19126 if (err < 0)
19127 return err;
19128 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019129}
19130
19131/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019132#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019133 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019134
19135static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19136 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019137 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019138{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019139 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019140 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019141
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019142 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019143 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020019144 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020019145 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019146 continue;
Takashi Iwai0e53f342011-04-07 12:27:32 +020019147 /* need the manual connection? */
19148 if (num > 1)
19149 snd_hda_codec_write(codec, nid, 0,
19150 AC_VERB_SET_CONNECT_SEL, i);
19151 /* unmute mixer widget inputs */
19152 snd_hda_codec_write(codec, srcs[i], 0,
19153 AC_VERB_SET_AMP_GAIN_MUTE,
19154 AMP_IN_UNMUTE(0));
19155 snd_hda_codec_write(codec, srcs[i], 0,
19156 AC_VERB_SET_AMP_GAIN_MUTE,
19157 AMP_IN_UNMUTE(1));
Takashi Iwai7085ec12009-10-02 09:03:58 +020019158 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019159 }
19160}
19161
19162static void alc662_auto_init_multi_out(struct hda_codec *codec)
19163{
19164 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019165 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019166 int i;
19167
19168 for (i = 0; i <= HDA_SIDE; i++) {
19169 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19170 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019171 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019172 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019173 }
19174}
19175
19176static void alc662_auto_init_hp_out(struct hda_codec *codec)
19177{
19178 struct alc_spec *spec = codec->spec;
19179 hda_nid_t pin;
19180
19181 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019182 if (pin)
19183 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19184 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019185 pin = spec->autocfg.speaker_pins[0];
19186 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019187 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19188 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019189}
19190
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019191#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19192
19193static void alc662_auto_init_analog_input(struct hda_codec *codec)
19194{
19195 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019196 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019197 int i;
19198
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019199 for (i = 0; i < cfg->num_inputs; i++) {
19200 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019201 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019202 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019203 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019204 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019205 snd_hda_codec_write(codec, nid, 0,
19206 AC_VERB_SET_AMP_GAIN_MUTE,
19207 AMP_OUT_MUTE);
19208 }
19209 }
19210}
19211
Takashi Iwaif511b012008-08-15 16:46:42 +020019212#define alc662_auto_init_input_src alc882_auto_init_input_src
19213
Takashi Iwaice764ab2011-04-27 16:35:23 +020019214/*
19215 * multi-io helper
19216 */
19217static int alc_auto_fill_multi_ios(struct hda_codec *codec,
19218 unsigned int location)
19219{
19220 struct alc_spec *spec = codec->spec;
19221 struct auto_pin_cfg *cfg = &spec->autocfg;
19222 int type, i, num_pins = 0;
19223
19224 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
19225 for (i = 0; i < cfg->num_inputs; i++) {
19226 hda_nid_t nid = cfg->inputs[i].pin;
19227 hda_nid_t dac;
19228 unsigned int defcfg, caps;
19229 if (cfg->inputs[i].type != type)
19230 continue;
19231 defcfg = snd_hda_codec_get_pincfg(codec, nid);
19232 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
19233 continue;
19234 if (location && get_defcfg_location(defcfg) != location)
19235 continue;
19236 caps = snd_hda_query_pin_caps(codec, nid);
19237 if (!(caps & AC_PINCAP_OUT))
19238 continue;
19239 dac = alc_auto_look_for_dac(codec, nid);
19240 if (!dac)
19241 continue;
19242 spec->multi_io[num_pins].pin = nid;
19243 spec->multi_io[num_pins].dac = dac;
19244 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +020019245 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +020019246 }
19247 }
19248 spec->multiout.num_dacs = 1;
19249 if (num_pins < 2)
19250 return 0;
19251 return num_pins;
19252}
19253
19254static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
19255 struct snd_ctl_elem_info *uinfo)
19256{
19257 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
19258 struct alc_spec *spec = codec->spec;
19259
19260 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
19261 uinfo->count = 1;
19262 uinfo->value.enumerated.items = spec->multi_ios + 1;
19263 if (uinfo->value.enumerated.item > spec->multi_ios)
19264 uinfo->value.enumerated.item = spec->multi_ios;
19265 sprintf(uinfo->value.enumerated.name, "%dch",
19266 (uinfo->value.enumerated.item + 1) * 2);
19267 return 0;
19268}
19269
19270static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
19271 struct snd_ctl_elem_value *ucontrol)
19272{
19273 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
19274 struct alc_spec *spec = codec->spec;
19275 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
19276 return 0;
19277}
19278
19279static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
19280{
19281 struct alc_spec *spec = codec->spec;
19282 hda_nid_t nid = spec->multi_io[idx].pin;
19283
19284 if (!spec->multi_io[idx].ctl_in)
19285 spec->multi_io[idx].ctl_in =
19286 snd_hda_codec_read(codec, nid, 0,
19287 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
19288 if (output) {
19289 snd_hda_codec_update_cache(codec, nid, 0,
19290 AC_VERB_SET_PIN_WIDGET_CONTROL,
19291 PIN_OUT);
19292 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
19293 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
19294 HDA_AMP_MUTE, 0);
19295 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
19296 } else {
19297 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
19298 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
19299 HDA_AMP_MUTE, HDA_AMP_MUTE);
19300 snd_hda_codec_update_cache(codec, nid, 0,
19301 AC_VERB_SET_PIN_WIDGET_CONTROL,
19302 spec->multi_io[idx].ctl_in);
19303 }
19304 return 0;
19305}
19306
19307static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
19308 struct snd_ctl_elem_value *ucontrol)
19309{
19310 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
19311 struct alc_spec *spec = codec->spec;
19312 int i, ch;
19313
19314 ch = ucontrol->value.enumerated.item[0];
19315 if (ch < 0 || ch > spec->multi_ios)
19316 return -EINVAL;
19317 if (ch == (spec->ext_channel_count - 1) / 2)
19318 return 0;
19319 spec->ext_channel_count = (ch + 1) * 2;
19320 for (i = 0; i < spec->multi_ios; i++)
19321 alc_set_multi_io(codec, i, i < ch);
19322 spec->multiout.max_channels = spec->ext_channel_count;
19323 return 1;
19324}
19325
Takashi Iwaia9111322011-05-02 11:30:18 +020019326static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +020019327 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
19328 .name = "Channel Mode",
19329 .info = alc_auto_ch_mode_info,
19330 .get = alc_auto_ch_mode_get,
19331 .put = alc_auto_ch_mode_put,
19332};
19333
19334static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
19335{
19336 struct alc_spec *spec = codec->spec;
19337 struct auto_pin_cfg *cfg = &spec->autocfg;
19338 unsigned int location, defcfg;
19339 int num_pins;
19340
19341 if (cfg->line_outs != 1 ||
19342 cfg->line_out_type != AUTO_PIN_LINE_OUT)
19343 return 0;
19344
19345 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
19346 location = get_defcfg_location(defcfg);
19347
19348 num_pins = alc_auto_fill_multi_ios(codec, location);
19349 if (num_pins > 0) {
19350 struct snd_kcontrol_new *knew;
19351
19352 knew = alc_kcontrol_new(spec);
19353 if (!knew)
19354 return -ENOMEM;
19355 *knew = alc_auto_channel_mode_enum;
19356 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
19357 if (!knew->name)
19358 return -ENOMEM;
19359
19360 spec->multi_ios = num_pins;
19361 spec->ext_channel_count = 2;
19362 spec->multiout.num_dacs = num_pins + 1;
19363 }
19364 return 0;
19365}
19366
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019367static int alc662_parse_auto_config(struct hda_codec *codec)
19368{
19369 struct alc_spec *spec = codec->spec;
19370 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019371 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019372
19373 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19374 alc662_ignore);
19375 if (err < 0)
19376 return err;
19377 if (!spec->autocfg.line_outs)
19378 return 0; /* can't find valid BIOS pin config */
19379
Takashi Iwai7085ec12009-10-02 09:03:58 +020019380 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019381 if (err < 0)
19382 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020019383 err = alc_auto_add_multi_channel_mode(codec);
19384 if (err < 0)
19385 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019386 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019387 if (err < 0)
19388 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019389 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019390 spec->autocfg.speaker_pins[0],
19391 "Speaker");
19392 if (err < 0)
19393 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019394 if (err)
19395 spec->multiout.extra_out_nid[0] = err;
19396 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019397 "Headphone");
19398 if (err < 0)
19399 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019400 if (err)
19401 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019402 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019403 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019404 return err;
19405
19406 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19407
Takashi Iwai757899a2010-07-30 10:48:14 +020019408 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019409
Takashi Iwai603c4012008-07-30 15:01:44 +020019410 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019411 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019412
19413 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019414 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019415
Takashi Iwaiee979a142008-09-02 15:42:20 +020019416 err = alc_auto_add_mic_boost(codec);
19417 if (err < 0)
19418 return err;
19419
Kailang Yang6227cdc2010-02-25 08:36:52 +010019420 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19421 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19422 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19423 else
19424 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019425
Takashi Iwai8c872862007-06-19 12:11:16 +020019426 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019427}
19428
19429/* additional initialization for auto-configuration model */
19430static void alc662_auto_init(struct hda_codec *codec)
19431{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019432 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019433 alc662_auto_init_multi_out(codec);
19434 alc662_auto_init_hp_out(codec);
19435 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019436 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019437 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019438 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019439 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019440}
19441
Todd Broch6be79482010-12-07 16:51:05 -080019442static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019443 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019444{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019445 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019446 return;
Todd Broch6be79482010-12-07 16:51:05 -080019447 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
19448 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
19449 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
19450 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
19451 (0 << AC_AMPCAP_MUTE_SHIFT)))
19452 printk(KERN_WARNING
19453 "hda_codec: failed to override amp caps for NID 0x2\n");
19454}
19455
David Henningsson6cb3b702010-09-09 08:51:44 +020019456enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019457 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019458 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080019459 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019460 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +020019461 ALC662_FIXUP_SKU_IGNORE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019462};
19463
19464static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019465 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019466 .type = ALC_FIXUP_PINS,
19467 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040019468 { 0x15, 0x99130112 }, /* subwoofer */
19469 { }
19470 }
19471 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019472 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019473 .type = ALC_FIXUP_PINS,
19474 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019475 { 0x17, 0x99130112 }, /* subwoofer */
19476 { }
19477 }
19478 },
Todd Broch6be79482010-12-07 16:51:05 -080019479 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019480 .type = ALC_FIXUP_FUNC,
19481 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019482 },
19483 [ALC662_FIXUP_CZC_P10T] = {
19484 .type = ALC_FIXUP_VERBS,
19485 .v.verbs = (const struct hda_verb[]) {
19486 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
19487 {}
19488 }
19489 },
David Henningsson94024cd2011-04-29 14:10:55 +020019490 [ALC662_FIXUP_SKU_IGNORE] = {
19491 .type = ALC_FIXUP_SKU,
19492 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +020019493 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019494};
19495
Takashi Iwaia9111322011-05-02 11:30:18 +020019496static const struct snd_pci_quirk alc662_fixup_tbl[] = {
David Henningssona6c47a82011-02-10 15:39:19 +010019497 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +020019498 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -040019499 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050019500 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019501 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019502 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010019503 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020019504 {}
19505};
19506
Todd Broch6be79482010-12-07 16:51:05 -080019507static const struct alc_model_fixup alc662_fixup_models[] = {
19508 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
19509 {}
19510};
David Henningsson6cb3b702010-09-09 08:51:44 +020019511
19512
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019513static int patch_alc662(struct hda_codec *codec)
19514{
19515 struct alc_spec *spec;
19516 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020019517 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019518
19519 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19520 if (!spec)
19521 return -ENOMEM;
19522
19523 codec->spec = spec;
19524
Kailang Yangda00c242010-03-19 11:23:45 +010019525 alc_auto_parse_customize_define(codec);
19526
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019527 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19528
Kailang Yang693194f2010-10-21 08:51:48 +020019529 coef = alc_read_coef_idx(codec, 0);
19530 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019531 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020019532 else if (coef & (1 << 14) &&
19533 codec->bus->pci->subsystem_vendor == 0x1025 &&
19534 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019535 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020019536 else if (coef == 0x4011)
19537 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010019538
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019539 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19540 alc662_models,
19541 alc662_cfg_tbl);
19542 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019543 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19544 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019545 board_config = ALC662_AUTO;
19546 }
19547
19548 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019549 alc_pick_fixup(codec, alc662_fixup_models,
19550 alc662_fixup_tbl, alc662_fixups);
19551 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019552 /* automatic parse from the BIOS config */
19553 err = alc662_parse_auto_config(codec);
19554 if (err < 0) {
19555 alc_free(codec);
19556 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020019557 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019558 printk(KERN_INFO
19559 "hda_codec: Cannot set up configuration "
19560 "from BIOS. Using base mode...\n");
19561 board_config = ALC662_3ST_2ch_DIG;
19562 }
19563 }
19564
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019565 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019566 err = snd_hda_attach_beep_device(codec, 0x1);
19567 if (err < 0) {
19568 alc_free(codec);
19569 return err;
19570 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019571 }
19572
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019573 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019574 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019575
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019576 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19577 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19578
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019579 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19580 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19581
Takashi Iwaidd704692009-08-11 08:45:11 +020019582 if (!spec->adc_nids) {
19583 spec->adc_nids = alc662_adc_nids;
19584 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19585 }
19586 if (!spec->capsrc_nids)
19587 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019588
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019589 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019590 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019591
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019592 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019593 switch (codec->vendor_id) {
19594 case 0x10ec0662:
19595 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19596 break;
19597 case 0x10ec0272:
19598 case 0x10ec0663:
19599 case 0x10ec0665:
19600 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19601 break;
19602 case 0x10ec0273:
19603 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19604 break;
19605 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019606 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019607 spec->vmaster_nid = 0x02;
19608
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019609 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
19610
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019611 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019612 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019613 spec->init_hook = alc662_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020019614 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +020019615
Kailang Yangbf1b0222010-10-21 08:49:56 +020019616 alc_init_jacks(codec);
19617
Takashi Iwaicb53c622007-08-10 17:21:45 +020019618#ifdef CONFIG_SND_HDA_POWER_SAVE
19619 if (!spec->loopback.amplist)
19620 spec->loopback.amplist = alc662_loopbacks;
19621#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019622
19623 return 0;
19624}
19625
Kailang Yang274693f2009-12-03 10:07:50 +010019626static int patch_alc888(struct hda_codec *codec)
19627{
19628 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19629 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010019630 if (codec->vendor_id == 0x10ec0887)
19631 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
19632 else
19633 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019634 if (!codec->chip_name) {
19635 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019636 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019637 }
19638 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019639 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019640 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019641}
19642
Kailang Yangb478b992011-05-18 11:51:15 +020019643static int patch_alc899(struct hda_codec *codec)
19644{
19645 if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
19646 kfree(codec->chip_name);
19647 codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
19648 }
19649 return patch_alc882(codec);
19650}
19651
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019652/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019653 * ALC680 support
19654 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019655#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019656#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19657#define alc680_modes alc260_modes
19658
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019659static const hda_nid_t alc680_dac_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019660 /* Lout1, Lout2, hp */
19661 0x02, 0x03, 0x04
19662};
19663
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019664static const hda_nid_t alc680_adc_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019665 /* ADC0-2 */
19666 /* DMIC, MIC, Line-in*/
19667 0x07, 0x08, 0x09
19668};
19669
Kailang Yangc69aefa2010-08-17 10:39:22 +020019670/*
19671 * Analog capture ADC cgange
19672 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019673static void alc680_rec_autoswitch(struct hda_codec *codec)
19674{
19675 struct alc_spec *spec = codec->spec;
19676 struct auto_pin_cfg *cfg = &spec->autocfg;
19677 int pin_found = 0;
19678 int type_found = AUTO_PIN_LAST;
19679 hda_nid_t nid;
19680 int i;
19681
19682 for (i = 0; i < cfg->num_inputs; i++) {
19683 nid = cfg->inputs[i].pin;
Takashi Iwai06dec222011-05-17 10:00:16 +020019684 if (!is_jack_detectable(codec, nid))
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019685 continue;
19686 if (snd_hda_jack_detect(codec, nid)) {
19687 if (cfg->inputs[i].type < type_found) {
19688 type_found = cfg->inputs[i].type;
19689 pin_found = nid;
19690 }
19691 }
19692 }
19693
19694 nid = 0x07;
19695 if (pin_found)
19696 snd_hda_get_connections(codec, pin_found, &nid, 1);
19697
19698 if (nid != spec->cur_adc)
19699 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19700 spec->cur_adc = nid;
19701 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19702 spec->cur_adc_format);
19703}
19704
Kailang Yangc69aefa2010-08-17 10:39:22 +020019705static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19706 struct hda_codec *codec,
19707 unsigned int stream_tag,
19708 unsigned int format,
19709 struct snd_pcm_substream *substream)
19710{
19711 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019712
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019713 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019714 spec->cur_adc_stream_tag = stream_tag;
19715 spec->cur_adc_format = format;
19716
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019717 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019718 return 0;
19719}
19720
19721static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19722 struct hda_codec *codec,
19723 struct snd_pcm_substream *substream)
19724{
19725 snd_hda_codec_cleanup_stream(codec, 0x07);
19726 snd_hda_codec_cleanup_stream(codec, 0x08);
19727 snd_hda_codec_cleanup_stream(codec, 0x09);
19728 return 0;
19729}
19730
Takashi Iwaia9111322011-05-02 11:30:18 +020019731static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019732 .substreams = 1, /* can be overridden */
19733 .channels_min = 2,
19734 .channels_max = 2,
19735 /* NID is set in alc_build_pcms */
19736 .ops = {
19737 .prepare = alc680_capture_pcm_prepare,
19738 .cleanup = alc680_capture_pcm_cleanup
19739 },
19740};
19741
Takashi Iwaia9111322011-05-02 11:30:18 +020019742static const struct snd_kcontrol_new alc680_base_mixer[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019743 /* output mixer control */
19744 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19745 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19746 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19747 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019748 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19749 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19750 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019751 { }
19752};
19753
Takashi Iwaia9111322011-05-02 11:30:18 +020019754static const struct hda_bind_ctls alc680_bind_cap_vol = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019755 .ops = &snd_hda_bind_vol,
19756 .values = {
19757 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19758 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19759 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19760 0
19761 },
19762};
19763
Takashi Iwaia9111322011-05-02 11:30:18 +020019764static const struct hda_bind_ctls alc680_bind_cap_switch = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019765 .ops = &snd_hda_bind_sw,
19766 .values = {
19767 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19768 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19769 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19770 0
19771 },
19772};
19773
Takashi Iwaia9111322011-05-02 11:30:18 +020019774static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019775 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19776 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019777 { } /* end */
19778};
19779
19780/*
19781 * generic initialization of ADC, input mixers and output mixers
19782 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019783static const struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019784 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19785 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19786 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019787
Kailang Yangc69aefa2010-08-17 10:39:22 +020019788 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19789 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19790 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19791 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19792 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19793 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019794
19795 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19796 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19797 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19798 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19799 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019800
19801 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19802 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019803 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019804
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019805 { }
19806};
19807
Kailang Yangc69aefa2010-08-17 10:39:22 +020019808/* toggle speaker-output according to the hp-jack state */
19809static void alc680_base_setup(struct hda_codec *codec)
19810{
19811 struct alc_spec *spec = codec->spec;
19812
19813 spec->autocfg.hp_pins[0] = 0x16;
19814 spec->autocfg.speaker_pins[0] = 0x14;
19815 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019816 spec->autocfg.num_inputs = 2;
19817 spec->autocfg.inputs[0].pin = 0x18;
19818 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19819 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019820 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Takashi Iwaid922b512011-04-28 12:18:53 +020019821 spec->automute = 1;
19822 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019823}
19824
19825static void alc680_unsol_event(struct hda_codec *codec,
19826 unsigned int res)
19827{
19828 if ((res >> 26) == ALC880_HP_EVENT)
Takashi Iwaid922b512011-04-28 12:18:53 +020019829 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019830 if ((res >> 26) == ALC880_MIC_EVENT)
19831 alc680_rec_autoswitch(codec);
19832}
19833
19834static void alc680_inithook(struct hda_codec *codec)
19835{
Takashi Iwaid922b512011-04-28 12:18:53 +020019836 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019837 alc680_rec_autoswitch(codec);
19838}
19839
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019840/* create input playback/capture controls for the given pin */
19841static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19842 const char *ctlname, int idx)
19843{
19844 hda_nid_t dac;
19845 int err;
19846
19847 switch (nid) {
19848 case 0x14:
19849 dac = 0x02;
19850 break;
19851 case 0x15:
19852 dac = 0x03;
19853 break;
19854 case 0x16:
19855 dac = 0x04;
19856 break;
19857 default:
19858 return 0;
19859 }
19860 if (spec->multiout.dac_nids[0] != dac &&
19861 spec->multiout.dac_nids[1] != dac) {
19862 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19863 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19864 HDA_OUTPUT));
19865 if (err < 0)
19866 return err;
19867
19868 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19869 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19870
19871 if (err < 0)
19872 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020019873 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019874 }
19875
19876 return 0;
19877}
19878
19879/* add playback controls from the parsed DAC table */
19880static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19881 const struct auto_pin_cfg *cfg)
19882{
19883 hda_nid_t nid;
19884 int err;
19885
19886 spec->multiout.dac_nids = spec->private_dac_nids;
19887
19888 nid = cfg->line_out_pins[0];
19889 if (nid) {
19890 const char *name;
19891 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19892 name = "Speaker";
19893 else
19894 name = "Front";
19895 err = alc680_new_analog_output(spec, nid, name, 0);
19896 if (err < 0)
19897 return err;
19898 }
19899
19900 nid = cfg->speaker_pins[0];
19901 if (nid) {
19902 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19903 if (err < 0)
19904 return err;
19905 }
19906 nid = cfg->hp_pins[0];
19907 if (nid) {
19908 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19909 if (err < 0)
19910 return err;
19911 }
19912
19913 return 0;
19914}
19915
19916static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19917 hda_nid_t nid, int pin_type)
19918{
19919 alc_set_pin_output(codec, nid, pin_type);
19920}
19921
19922static void alc680_auto_init_multi_out(struct hda_codec *codec)
19923{
19924 struct alc_spec *spec = codec->spec;
19925 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19926 if (nid) {
19927 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19928 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19929 }
19930}
19931
19932static void alc680_auto_init_hp_out(struct hda_codec *codec)
19933{
19934 struct alc_spec *spec = codec->spec;
19935 hda_nid_t pin;
19936
19937 pin = spec->autocfg.hp_pins[0];
19938 if (pin)
19939 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19940 pin = spec->autocfg.speaker_pins[0];
19941 if (pin)
19942 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19943}
19944
19945/* pcm configuration: identical with ALC880 */
19946#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19947#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19948#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19949#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019950#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019951
19952/*
19953 * BIOS auto configuration
19954 */
19955static int alc680_parse_auto_config(struct hda_codec *codec)
19956{
19957 struct alc_spec *spec = codec->spec;
19958 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019959 static const hda_nid_t alc680_ignore[] = { 0 };
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019960
19961 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19962 alc680_ignore);
19963 if (err < 0)
19964 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019965
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019966 if (!spec->autocfg.line_outs) {
19967 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19968 spec->multiout.max_channels = 2;
19969 spec->no_analog = 1;
19970 goto dig_only;
19971 }
19972 return 0; /* can't find valid BIOS pin config */
19973 }
19974 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19975 if (err < 0)
19976 return err;
19977
19978 spec->multiout.max_channels = 2;
19979
19980 dig_only:
19981 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019982 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019983 if (spec->kctls.list)
19984 add_mixer(spec, spec->kctls.list);
19985
19986 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019987
19988 err = alc_auto_add_mic_boost(codec);
19989 if (err < 0)
19990 return err;
19991
19992 return 1;
19993}
19994
19995#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19996
19997/* init callback for auto-configuration model -- overriding the default init */
19998static void alc680_auto_init(struct hda_codec *codec)
19999{
20000 struct alc_spec *spec = codec->spec;
20001 alc680_auto_init_multi_out(codec);
20002 alc680_auto_init_hp_out(codec);
20003 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020020004 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020005 if (spec->unsol_event)
20006 alc_inithook(codec);
20007}
20008
20009/*
20010 * configuration and preset
20011 */
Takashi Iwaiea734962011-01-17 11:29:34 +010020012static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020020013 [ALC680_BASE] = "base",
20014 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020015};
20016
Takashi Iwaia9111322011-05-02 11:30:18 +020020017static const struct snd_pci_quirk alc680_cfg_tbl[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020018 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
20019 {}
20020};
20021
Takashi Iwaia9111322011-05-02 11:30:18 +020020022static const struct alc_config_preset alc680_presets[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020023 [ALC680_BASE] = {
20024 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020020025 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020026 .init_verbs = { alc680_init_verbs },
20027 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
20028 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020029 .dig_out_nid = ALC680_DIGOUT_NID,
20030 .num_channel_mode = ARRAY_SIZE(alc680_modes),
20031 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020020032 .unsol_event = alc680_unsol_event,
20033 .setup = alc680_base_setup,
20034 .init_hook = alc680_inithook,
20035
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020036 },
20037};
20038
20039static int patch_alc680(struct hda_codec *codec)
20040{
20041 struct alc_spec *spec;
20042 int board_config;
20043 int err;
20044
20045 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
20046 if (spec == NULL)
20047 return -ENOMEM;
20048
20049 codec->spec = spec;
20050
20051 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
20052 alc680_models,
20053 alc680_cfg_tbl);
20054
20055 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
20056 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
20057 codec->chip_name);
20058 board_config = ALC680_AUTO;
20059 }
20060
20061 if (board_config == ALC680_AUTO) {
20062 /* automatic parse from the BIOS config */
20063 err = alc680_parse_auto_config(codec);
20064 if (err < 0) {
20065 alc_free(codec);
20066 return err;
20067 } else if (!err) {
20068 printk(KERN_INFO
20069 "hda_codec: Cannot set up configuration "
20070 "from BIOS. Using base mode...\n");
20071 board_config = ALC680_BASE;
20072 }
20073 }
20074
20075 if (board_config != ALC680_AUTO)
20076 setup_preset(codec, &alc680_presets[board_config]);
20077
20078 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020079 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020080 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020081 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020082
20083 if (!spec->adc_nids) {
20084 spec->adc_nids = alc680_adc_nids;
20085 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
20086 }
20087
20088 if (!spec->cap_mixer)
20089 set_capture_mixer(codec);
20090
20091 spec->vmaster_nid = 0x02;
20092
20093 codec->patch_ops = alc_patch_ops;
20094 if (board_config == ALC680_AUTO)
20095 spec->init_hook = alc680_auto_init;
20096
20097 return 0;
20098}
20099
20100/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070020101 * patch entries
20102 */
Takashi Iwaia9111322011-05-02 11:30:18 +020020103static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +020020104 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020105 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020106 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020107 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020020108 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020109 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020110 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020020111 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020112 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +020020113 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020114 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020115 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020116 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
20117 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
20118 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020119 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020020120 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020121 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
20122 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020020123 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010020124 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010020125 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020126 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020127 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020128 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020020129 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020020130 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020131 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020020132 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020133 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020134 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010020135 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020020136 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020020137 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020138 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020020139 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020140 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Kailang Yangb478b992011-05-18 11:51:15 +020020141 { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020142 {} /* terminator */
20143};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020144
20145MODULE_ALIAS("snd-hda-codec-id:10ec*");
20146
20147MODULE_LICENSE("GPL");
20148MODULE_DESCRIPTION("Realtek HD-audio codec");
20149
20150static struct hda_codec_preset_list realtek_list = {
20151 .preset = snd_hda_preset_realtek,
20152 .owner = THIS_MODULE,
20153};
20154
20155static int __init patch_realtek_init(void)
20156{
20157 return snd_hda_add_codec_preset(&realtek_list);
20158}
20159
20160static void __exit patch_realtek_exit(void)
20161{
20162 snd_hda_delete_codec_preset(&realtek_list);
20163}
20164
20165module_init(patch_realtek_init)
20166module_exit(patch_realtek_exit)